Attaching text to mid-points of SKPath segments

jmainhartjmainhart USMember ✭✭

I'm currently working on a project that ingests a set of vectors and spits out a sketch. The vectors follow the following format:

S-A,U024,R018,D024,L018,E---
S-P,R018,D006,L018,U006,E---
U024,R004,S-D,U012,R014,D012,L014,E---
S-1,L012,U016,R012,D016,E---
R018,S-1,U016,R012,D016,L012,E---

I was able to get the image to draw somewhat correctly (it's getting flipped on resize for some reason...) but I have been unable to get numbers to display or attach themselves to the middle of each segment of the path.

Here is my code to show my current approach (I would provide a .NET Fiddle but I'm to new..).

using System;
using System.IO;
using SkiaSharp;
using System.Collections.Generic;

namespace Sketch
{
    public class Program
    {
        private const string Vectors = "S-A,U024,R018,D024,L018,E---,S-P,R018,D006,L018,U006,E---,U024,R004,S-D,U012,R014,D012,L014,E---,S-     1,L012,U016,R012,D016,E---,R018,S-1,U016,R012,D016,L012,E---";
        private const string Suffix = "E---";
        private const string Prefixes = "S-A,S-P,S-D,S-1,S-1";
        private const string BaseDirPath = "C:\Sketches";
        public static void Main()
        {
            Directory.CreateDirectory(BaseDirPath);
            var info = new SKImageInfo(500, 500, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
            var paths = BuildPaths(Vectors.Split(new[]{Suffix}, StringSplitOptions.RemoveEmptyEntries), Prefixes.Split(','));
            var drawPath = BuildDrawPath(paths);
            ResizePath(drawPath, info);
            using (var surface = SKSurface.Create(info))
            {
                var canvas = surface.Canvas;
                canvas.Clear(SKColors.White);
                using (var paint = new SKPaint())
                {
                    paint.Style = SKPaintStyle.Stroke;
                    paint.Color = SKColors.Black;
                    canvas.DrawPath(drawPath, paint);
                }

                    var pngEncodedFile = surface.Snapshot().Encode().ToArray();
                        File.WriteAllBytes(BaseDirPath + "/demo.png", pngEncodedFile);
                }
            }

            private static void ResizePath(SKPath drawPath, SKImageInfo info)
            {
                 var canvasRect = SKRect.Create(info.Size);
                //I need to find the size of the path
                 var pathRect = drawPath.TightBounds;
                //I want to find the largest rectangle that can fit on my canvas maintaining the path's aspect ratio
                var drawPathRect = canvasRect.AspectFit(pathRect.Size);
                //Now I need to transform the path to draw within the drawPathRect
                //First translate original path to its own origin
                var firstTranslateM = SKMatrix.MakeTranslation(-pathRect.Left, -pathRect.Top);
                //Next handle scaling.  Since I maintained aspect ratio, I should be able to use either
                //width or height to figure out scaling factor
                var scalingFactor = drawPathRect.Width / pathRect.Width;
                var scaleM = SKMatrix.MakeScale(scalingFactor, scalingFactor);
                //Next I need to handle translation so path is centered on canvas
                var secondTranslateM = SKMatrix.MakeTranslation(drawPathRect.Left, drawPathRect.Top);
                //Finally I need to handle transforming the path to rotate 180 degrees
                var rotationMatrix = SKMatrix.MakeRotationDegrees(180, drawPathRect.MidX, drawPathRect.MidY);
                //Now combine the translation, scaling, and translation into a single matrix by matrix multiplication/concatentation
                var transformM = SKMatrix.MakeIdentity();
                SKMatrix.PostConcat(ref transformM, firstTranslateM);
                SKMatrix.PostConcat(ref transformM, scaleM);
                SKMatrix.PostConcat(ref transformM, secondTranslateM);
                SKMatrix.PostConcat(ref transformM, rotationMatrix);
                //Now apply the transform to the path
                drawPath.Transform(transformM);
            }

            private static List<SKPath> BuildPaths(IEnumerable<string> sketchVectors, ICollection<string> prefixes)
            {
                var paths = new List<SKPath>();
                foreach (var pathVector in sketchVectors)
                {
                        var path = new SKPath();
                        var vector = pathVector.TrimEnd(',').TrimStart(',');
                        var IsMove = true;
                        foreach (var x in vector.Split(','))
                        {
                            if (prefixes.Contains(x))
                            {
                                    IsMove = false;
                            }
                            else
                            {
                                    var distance = Convert.ToInt32(x.Substring(1));
                                    switch (x[0])
                                    {
                                        case 'U':
                                                if (IsMove)
                                                {
                                                    MoveUp(path, distance);
                                                }
                                                else
                                                {
                                                    LineUp(path, distance);
                                                }   
                                              break;
                                        case 'D':
                                                if (IsMove)
                                                {
                                                    MoveDown(path, distance);
                                                }
                                                else
                                                {
                                                    LineDown(path, distance);
                                                }
                                          break;
                                        case 'L':
                                                if (IsMove)
                                                {
                                                    MoveLeft(path, distance);
                                                }
                                                else
                                                {
                                                    LineLeft(path, distance);
                                                }
                                              break;
                                        case 'R':
                                                if (IsMove)
                                                {
                                                    MoveRight(path, distance);
                                                }
                                                else
                                                {
                                                    LineRight(path, distance);
                                                }
                                              break;
                                    }
                            }
                        }
                    paths.Add(path);
                }
                return paths;
            }

            private static SKPath BuildDrawPath(IEnumerable<SKPath> paths)
            {
                var path = new SKPath();
                foreach (var p in paths)
                {
                        path.AddPath(p);
                }

                return path;
            }

            private static void LineUp(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X, Y = path.LastPoint.Y + vector};
                path.LineTo(point);
            }

            private static void LineDown(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X, Y = path.LastPoint.Y - vector};
                path.LineTo(point);
            }

            private static void LineRight(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X + vector, Y = path.LastPoint.Y};
                path.LineTo(point);
            }

            private static void LineLeft(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X - vector, Y = path.LastPoint.Y};
                path.LineTo(point);
            }

            private static void MoveUp(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X, Y = path.LastPoint.Y + vector};
                path.LineTo(point);
            }

            private static void MoveDown(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X, Y = path.LastPoint.Y - vector};
                path.MoveTo(point);
            }

            private static void MoveRight(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X + vector, Y = path.LastPoint.Y};
                path.LineTo(point);
            }

            private static void MoveLeft(SKPath path, float vector)
            {
                var point = new SKPoint{X = path.LastPoint.X - vector, Y = path.LastPoint.Y};
                path.LineTo(point);
            }
    }
}
Sign In or Register to comment.