Skip to content

Commit

Permalink
Make PathCollectionConverter bi-directional
Browse files Browse the repository at this point in the history
  • Loading branch information
Edward Miller committed Jan 15, 2024
1 parent 65e950d commit df6de3d
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 3 deletions.
95 changes: 93 additions & 2 deletions src/Controls/src/Core/Shapes/PathFigureCollectionConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;

Expand All @@ -14,7 +16,7 @@ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceT
=> sourceType == typeof(string);

public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
=> false;
=> destinationType == typeof(string);

const bool AllowSign = true;
const bool AllowComma = true;
Expand Down Expand Up @@ -581,8 +583,97 @@ void SkipDigits(bool signAllowed)
}
}

private static string ParsePathFigureCollectionToString(PathFigureCollection pathFigureCollection)
{
var sb = new StringBuilder();

foreach (var pathFigure in pathFigureCollection)
{
sb.Append('M')
.Append(pathFigure.StartPoint.X.ToString("R"))
.Append(',')
.Append(pathFigure.StartPoint.Y.ToString("R"))
.Append(' ');

foreach (var pathSegment in pathFigure.Segments)
{
if (pathSegment is LineSegment lineSegment)
{
sb.Append('L')
.Append(lineSegment.Point.X.ToString("R"))
.Append(',')
.Append(lineSegment.Point.Y.ToString("R"))
.Append(' ');
}
else if (pathSegment is BezierSegment bezierSegment)
{
sb.Append('C')
.Append(bezierSegment.Point1.X.ToString("R"))
.Append(',')
.Append(bezierSegment.Point1.Y.ToString("R"))
.Append(' ')
.Append(bezierSegment.Point2.X.ToString("R"))
.Append(',')
.Append(bezierSegment.Point2.Y.ToString("R"))
.Append(' ')
.Append(bezierSegment.Point3.X.ToString("R"))
.Append(',')
.Append(bezierSegment.Point3.Y.ToString("R"))
.Append(' ');
}
else if (pathSegment is QuadraticBezierSegment quadraticBezierSegment)
{
sb.Append('Q')
.Append(quadraticBezierSegment.Point1.X.ToString("R"))
.Append(',')
.Append(quadraticBezierSegment.Point1.Y.ToString("R"))
.Append(' ')
.Append(quadraticBezierSegment.Point2.X.ToString("R"))
.Append(',')
.Append(quadraticBezierSegment.Point2.Y.ToString("R"))
.Append(' ');
}
else if (pathSegment is ArcSegment arcSegment)
{
sb.Append('A')
.Append(arcSegment.Size.Width)
.Append(',')
.Append(arcSegment.Size.Height)
.Append(' ')
.Append(arcSegment.RotationAngle)
.Append(' ')
.Append(arcSegment.IsLargeArc ? "1" : "0")
.Append(',')
.Append(arcSegment.SweepDirection == SweepDirection.Clockwise ? "1" : "0")
.Append(' ')
.Append(arcSegment.Point.X.ToString("R"))
.Append(',')
.Append(arcSegment.Point.Y.ToString("R"))
.Append(' ');
}
}

if (pathFigure.IsClosed)
{
sb.Append('Z');
}

sb.Append(' ');
}

sb.Length = sb.Length - 1;

return sb.ToString();
}

public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
=> throw new NotSupportedException();
{
if (value is PathFigureCollection pathFigureCollection)
{
return ParsePathFigureCollectionToString(pathFigureCollection);
}

throw new InvalidDataException($"Value is not of type {nameof(PathFigureCollection)}");
}
}
}
15 changes: 14 additions & 1 deletion src/Controls/tests/Core.UnitTests/PathFigureCollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace Microsoft.Maui.Controls.Core.UnitTests
{
public class PathFigureCollectionTests
{
const string testPath = "M10,100 C100,0 200,200 300,100";

PathFigureCollectionConverter _pathFigureCollectionConverter;

public PathFigureCollectionTests()
Expand All @@ -16,12 +18,23 @@ public PathFigureCollectionTests()
[Fact]
public void ConvertStringToPathFigureCollectionTest()
{
PathFigureCollection result = _pathFigureCollectionConverter.ConvertFromInvariantString("M 10,100 C 100,0 200,200 300,100") as PathFigureCollection;
PathFigureCollection result = _pathFigureCollectionConverter.ConvertFromInvariantString(testPath) as PathFigureCollection;

Assert.NotNull(result);
Assert.Single(result);
}

[Fact]
public void ConvertPathFigureCollectionToStringTest()
{
PathFigureCollection result = _pathFigureCollectionConverter.ConvertFromInvariantString(testPath) as PathFigureCollection;
string pathString = _pathFigureCollectionConverter.ConvertTo(result, typeof(string)) as string;

Assert.NotNull(result);
Assert.NotNull(pathString);
Assert.Equal(testPath, pathString);
}

[Theory]
[InlineData("M8.4580019,25.5C8.4580019,26.747002 10.050002,27.758995 12.013003,27.758995 13.977001,27.758995 15.569004,26.747002 15.569004,25.5z M19.000005,10C16.861005,9.9469986 14.527004,12.903999 14.822002,22.133995 14.822002,22.133995 26.036002,15.072998 20.689,10.681999 20.183003,10.265999 19.599004,10.014999 19.000005,10z M4.2539991,10C3.6549998,10.014999 3.0710002,10.265999 2.5649996,10.681999 -2.7820019,15.072998 8.4320009,22.133995 8.4320009,22.133995 8.7270001,12.903999 6.3929995,9.9469986 4.2539991,10z M11.643,0C18.073003,0 23.286002,5.8619995 23.286002,13.091995 23.286002,20.321999 18.684003,32 12.254,32 5.8239992,32 1.8224728E-07,20.321999 0,13.091995 1.8224728E-07,5.8619995 5.2129987,0 11.643,0z", "AlienPathTest")]
[InlineData("M16.484421,0.73799322C20.831404,0.7379931 24.353395,1.1259904 24.353395,1.6049905 24.353395,2.0839829 20.831404,2.4719803 16.484421,2.47198 12.138443,2.4719803 8.6154527,2.0839829 8.6154527,1.6049905 8.6154527,1.1259904 12.138443,0.7379931 16.484421,0.73799322z M1.9454784,0.061995983C2.7564723,5.2449602 12.246436,11.341911 12.246436,11.341911 13.248431,19.240842 9.6454477,17.915854 9.6454477,17.915854 7.9604563,18.897849 6.5314603,17.171859 6.5314603,17.171859 4.1084647,18.29585 3.279473,15.359877 3.2794733,15.359877 0.82348057,15.291876 1.2804796,11.362907 1.2804799,11.362907 -1.573514,10.239915 1.2344746,6.3909473 1.2344746,6.3909473 -1.3255138,4.9869594 1.9454782,0.061996057 1.9454784,0.061995983z M30.054371,0C30.054371,9.8700468E-08 33.325355,4.9249634 30.765367,6.3289513 30.765367,6.3289513 33.574364,10.177919 30.71837,11.30191 30.71837,11.30191 31.175369,15.22988 28.721384,15.297872 28.721384,15.297872 27.892376,18.232854 25.468389,17.110862 25.468389,17.110862 24.040392,18.835847 22.355402,17.853852 22.355402,17.853852 18.752417,19.178845 19.753414,11.279907 19.753414,11.279907 29.243385,5.1829566 30.054371,0z", "AngelPathTest")]
Expand Down

0 comments on commit df6de3d

Please sign in to comment.