Search code examples
c#graphicspathskiasharp

Does SkiaSharp have an equivalent Flatten method to System.Drawing?


I have hit a road block using SkiaSharp recently. I have been porting older code from System.Drawing to SkiaSharp. The GraphicsPath class had a flatten method which converted the curves to a series of connected line segments.

https://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.graphicspath.flatten(v=vs.110).aspx

I cannot seem to find an equivalent method for SkiaSharp. The SKPath Simplify method seems a bit hazy on what it actually does. In my testing it didn't appear to produce a flattened path.

https://developer.xamarin.com/api/member/SkiaSharp.SKPath.Simplify()/


Solution

  • At some point after I asked this question Xamarin added documentation to do this. It is located here

    https://developer.xamarin.com/guides/xamarin-forms/advanced/skiasharp/curves/information/

    static class PathExtensions
    {
    public static SKPath CloneWithTransform(this SKPath pathIn, Func<SKPoint, SKPoint> transform)
    {
        SKPath pathOut = new SKPath();
    
        using (SKPath.RawIterator iterator = pathIn.CreateRawIterator())
        {
            SKPoint[] points = new SKPoint[4];
            SKPathVerb pathVerb = SKPathVerb.Move;
            SKPoint firstPoint = new SKPoint();
            SKPoint lastPoint = new SKPoint();
    
            while ((pathVerb = iterator.Next(points)) != SKPathVerb.Done)
            {
                switch (pathVerb)
                {
                    case SKPathVerb.Move:
                        pathOut.MoveTo(transform(points[0]));
                        firstPoint = lastPoint = points[0];
                        break;
    
                    case SKPathVerb.Line:
                        SKPoint[] linePoints = Interpolate(points[0], points[1]);
    
                        foreach (SKPoint pt in linePoints)
                        {
                            pathOut.LineTo(transform(pt));
                        }
    
                        lastPoint = points[1];
                        break;
    
                    case SKPathVerb.Cubic:
                        SKPoint[] cubicPoints = FlattenCubic(points[0], points[1], points[2], points[3]);
    
                        foreach (SKPoint pt in cubicPoints)
                        {
                            pathOut.LineTo(transform(pt));
                        }
    
                        lastPoint = points[3];
                        break;
    
                    case SKPathVerb.Quad:
                        SKPoint[] quadPoints = FlattenQuadratic(points[0], points[1], points[2]);
    
                        foreach (SKPoint pt in quadPoints)
                        {
                            pathOut.LineTo(transform(pt));
                        }
    
                        lastPoint = points[2];
                        break;
    
                    case SKPathVerb.Conic:
                        SKPoint[] conicPoints = FlattenConic(points[0], points[1], points[2], iterator.ConicWeight());
    
                        foreach (SKPoint pt in conicPoints)
                        {
                            pathOut.LineTo(transform(pt));
                        }
    
                        lastPoint = points[2];
                        break;
    
                    case SKPathVerb.Close:
                        SKPoint[] closePoints = Interpolate(lastPoint, firstPoint);
    
                        foreach (SKPoint pt in closePoints)
                        {
                            pathOut.LineTo(transform(pt));
                        }
    
                        firstPoint = lastPoint = new SKPoint(0, 0);
                        pathOut.Close();
                        break;
                }
            }
        }
        return pathOut;
    }
    ...
    }