Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Android, iOS] Fix issue using ArcSegment to create a Path #11195

Merged
merged 15 commits into from
Aug 24, 2020
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8" ?>
<controls:TestContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
x:Class="Xamarin.Forms.Controls.Issues.Issue11190"
Title="Issue 11190">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label
Padding="12"
BackgroundColor="Black"
TextColor="White"
Text="If the Shape is rendered without problems or exceptions, the test has passed."/>
<Grid
Grid.Row="1"
HorizontalOptions="Start"
VerticalOptions="Start"
HeightRequest="200"
WidthRequest="200">
<Path
Stroke="Black"
HeightRequest="200"
WidthRequest="200">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure
StartPoint="0,0">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment
Size="100,100"
RotationAngle="45"
IsLargeArc="True"
SweepDirection="CounterClockwise"
Point="100,100" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Grid>
</controls:TestContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.Collections.Generic;

#if UITEST && __ANDROID__
using Xamarin.UITest;
using Xamarin.UITest.Queries;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
using System.Linq;
#endif

namespace Xamarin.Forms.Controls.Issues
{
#if UITEST && __ANDROID__
[Category(UITestCategories.Shape)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 11190, "[Bug] Shapes: ArcSegment throwing on iOS, doing nothing on Android", PlatformAffected.Android | PlatformAffected.iOS)]
public partial class Issue11190 : TestContentPage
{

public Issue11190()
{
#if APP
Device.SetFlags(new List<string> { ExperimentalFlags.ShapesExperimental });
InitializeComponent();
#endif
}


protected override void Init()
{

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue11031.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11018.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue10940.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11190.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11050.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue9456.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue10908.xaml.cs" />
Expand Down Expand Up @@ -1714,6 +1715,9 @@
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue9555.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue11190.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)RectTest.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
Expand Down
2 changes: 1 addition & 1 deletion Xamarin.Forms.Core.UITests.Shared/UITestCategories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ internal static class UITestCategories
public const string Github5000 = "Github5000";
public const string Github10000 = "Github10000";
public const string RadioButton = "RadioButton";
public const string Accessibility = "Accessibility";
public const string Shape = "Shape";
public const string Accessibility = "Accessibility";
public const string Brush = "Brush";
}
}
71 changes: 71 additions & 0 deletions Xamarin.Forms.Core.UnitTests/GeometryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.Collections.Generic;
using NUnit.Framework;
using Xamarin.Forms.Shapes;

namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class GeometryTests : BaseTestFixture
{
[SetUp]
public override void Setup()
{
base.Setup();

Device.SetFlags(new[] { ExperimentalFlags.ShapesExperimental });
}

[TestCase(0, true)]
[TestCase(0, false)]
[TestCase(45, true)]
[TestCase(45, false)]
[TestCase(180, true)]
[TestCase(180, false)]
[TestCase(270, true)]
[TestCase(270, false)]
public void FlattenArcTest(double angle, bool isLargeArc)
{
var path = new Path
{
HeightRequest = 200,
WidthRequest = 200,
Stroke = Brush.Black
};

PathFigure figure = new PathFigure();

ArcSegment arcSegment = new ArcSegment
{
Point = new Point(10, 100),
Size = new Size(100, 50),
RotationAngle = angle,
IsLargeArc = isLargeArc
};

figure.Segments.Add(arcSegment);

path.Data = new PathGeometry
{
Figures = new PathFigureCollection
{
figure
}
};

List<Point> points = new List<Point>();

GeometryHelper.FlattenArc(
points,
Point.Zero,
arcSegment.Point,
arcSegment.Size.Width,
arcSegment.Size.Height,
arcSegment.RotationAngle,
arcSegment.IsLargeArc,
arcSegment.SweepDirection == SweepDirection.CounterClockwise,
1);

Assert.AreNotEqual(0, points.Count);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@
<Compile Include="PolylineTests.cs" />
<Compile Include="RectangleTests.cs" />
<Compile Include="LineTests.cs" />
<Compile Include="GeometryTests.cs" />
<Compile Include="RectUnitTests.cs" />
<Compile Include="BrushUnitTests.cs" />
<Compile Include="LinearGradientBrushTests.cs" />
Expand Down
22 changes: 14 additions & 8 deletions Xamarin.Forms.Core/Shapes/GeometryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,19 @@ public static void FlattenGeometry(PathGeometry pathGeoDst, Geometry geoSrc, dou
else if (segSrc is ArcSegment)
{
ArcSegment arcSeg = segSrc as ArcSegment;

Points.Clear();

FlattenArc(Points, ptLast, arcSeg.Point,
arcSeg.Size.Width, arcSeg.Size.Height,
arcSeg.RotationAngle,
arcSeg.IsLargeArc,
arcSeg.SweepDirection == SweepDirection.CounterClockwise,
tolerance);
FlattenArc(
Points,
ptLast,
arcSeg.Point,
arcSeg.Size.Width,
arcSeg.Size.Height,
arcSeg.RotationAngle,
arcSeg.IsLargeArc,
arcSeg.SweepDirection == SweepDirection.CounterClockwise,
tolerance);

// Set ptLast while transferring points
for (int i = 1; i < Points.Count; i++)
Expand Down Expand Up @@ -260,6 +265,7 @@ public static void FlattenQuadraticBezier(List<Point> points, Point ptStart, Poi
}
}

// More information: http://www.charlespetzold.com/blog/2008/01/Mathematics-of-ArcSegment.html
public static void FlattenArc(List<Point> points, Point pt1, Point pt2, double radiusX, double radiusY, double angleRotation,
bool isLargeArc, bool isCounterclockwise, double tolerance)
{
Expand All @@ -285,8 +291,8 @@ public static void FlattenArc(List<Point> points, Point pt1, Point pt2, double r

vectRotated = vectRotated.Normalized;

// Distance from chord to center
double centerDistance = Math.Sqrt(radiusY * radiusY - halfChord * halfChord);
// Distance from chord to center
double centerDistance = Math.Sqrt(Math.Abs((radiusY * radiusY) - (halfChord * halfChord)));

// Calculate center point
Point center = midPoint + centerDistance * vectRotated;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ public static APath ToAPath(this Geometry geometry, Context context)

List<Point> points = new List<Point>();

GeometryHelper.FlattenArc(points,
GeometryHelper.FlattenArc(
points,
lastPoint,
arcSegment.Point,
arcSegment.Size.Width,
Expand Down
5 changes: 3 additions & 2 deletions Xamarin.Forms.Platform.iOS/Extensions/GeometryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ public static PathData ToCGPath(this Geometry geometry, Transform renderTransfor

List<Point> points = new List<Point>();

GeometryHelper.FlattenArc(points,
GeometryHelper.FlattenArc(
points,
lastPoint,
arcSegment.Point,
arcSegment.Size.Width,
Expand All @@ -179,7 +180,7 @@ public static PathData ToCGPath(this Geometry geometry, Transform renderTransfor

pathData.Data.AddLines(cgpoints);

lastPoint = points[points.Count - 1];
lastPoint = points.Count > 0 ? points[points.Count - 1] : Point.Zero;
}
}

Expand Down