From 748c3a3208861c83d8534aac8a4f5ad7426f1ad4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 19 Jan 2022 20:38:23 +0000 Subject: [PATCH] Merge pull request #7395 from hacklex/feature/PreciseArcTo Fixed and exposed PreciseArcTo for ellipses with extreme width:height ratios --- .../Media/PreciseEllipticArcHelper.cs} | 45 ++++++++++---- .../Media/StreamGeometryContext.cs | 24 ++++++++ .../RenderHelpers/RenderHelpers.projitems | 1 - .../Media/StreamGeometryTests.cs | 56 ++++++++++++++++++ ...cs_In_All_Directions.deferred.expected.png | Bin 0 -> 6332 bytes ...s_In_All_Directions.immediate.expected.png | Bin 0 -> 6332 bytes ...cs_In_All_Directions.deferred.expected.png | Bin 0 -> 5828 bytes ...s_In_All_Directions.immediate.expected.png | Bin 0 -> 5828 bytes 8 files changed, 112 insertions(+), 14 deletions(-) rename src/{Shared/RenderHelpers/ArcToHelper.cs => Avalonia.Visuals/Media/PreciseEllipticArcHelper.cs} (97%) create mode 100644 tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs create mode 100644 tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png create mode 100644 tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png create mode 100644 tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png create mode 100644 tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png diff --git a/src/Shared/RenderHelpers/ArcToHelper.cs b/src/Avalonia.Visuals/Media/PreciseEllipticArcHelper.cs similarity index 97% rename from src/Shared/RenderHelpers/ArcToHelper.cs rename to src/Avalonia.Visuals/Media/PreciseEllipticArcHelper.cs index 0bbf451970..5dd647e8ca 100644 --- a/src/Shared/RenderHelpers/ArcToHelper.cs +++ b/src/Avalonia.Visuals/Media/PreciseEllipticArcHelper.cs @@ -1,5 +1,6 @@ // Copyright © 2003-2004, Luc Maisonobe // 2015 - Alexey Rozanov - Adaptations for Avalonia and oval center computations +// 2022 - Alexey Rozanov - Fix for arcs sometimes drawn in inverted order. // All rights reserved. // // Redistribution and use in source and binary forms, with @@ -49,12 +50,10 @@ // Adapted from http://www.spaceroots.org/documents/ellipse/EllipticalArc.java using System; -using Avalonia.Media; -using Avalonia.Platform; -namespace Avalonia.RenderHelpers +namespace Avalonia.Media { - static class ArcToHelper + static class PreciseEllipticArcHelper { /// /// This class represents an elliptical arc on a 2D plane. @@ -292,6 +291,8 @@ namespace Avalonia.RenderHelpers /// internal double G2; + public bool DrawInOppositeDirection { get; set; } + /// /// Builds an elliptical arc composed of the full unit circle around (0,0) /// @@ -850,7 +851,7 @@ namespace Avalonia.RenderHelpers /// Builds the arc outline using given StreamGeometryContext and default (max) Bezier curve degree and acceptable error of half a pixel (0.5) /// /// A StreamGeometryContext to output the path commands to - public void BuildArc(IStreamGeometryContextImpl path) + public void BuildArc(StreamGeometryContext path) { BuildArc(path, _maxDegree, _defaultFlatness, true); } @@ -862,7 +863,7 @@ namespace Avalonia.RenderHelpers /// degree of the Bezier curve to use /// acceptable error /// if true, a new figure will be started in the specified StreamGeometryContext - public void BuildArc(IStreamGeometryContextImpl path, int degree, double threshold, bool openNewFigure) + public void BuildArc(StreamGeometryContext path, int degree, double threshold, bool openNewFigure) { if (degree < 1 || degree > _maxDegree) throw new ArgumentException($"degree should be between {1} and {_maxDegree}", nameof(degree)); @@ -888,8 +889,18 @@ namespace Avalonia.RenderHelpers } n = n << 1; } - dEta = (Eta2 - Eta1) / n; - etaB = Eta1; + if (!DrawInOppositeDirection) + { + dEta = (Eta2 - Eta1) / n; + etaB = Eta1; + } + else + { + dEta = (Eta1 - Eta2) / n; + etaB = Eta2; + } + + double cosEtaB = Math.Cos(etaB); double sinEtaB = Math.Sin(etaB); double aCosEtaB = A * cosEtaB; @@ -922,6 +933,7 @@ namespace Avalonia.RenderHelpers */ //otherwise we're supposed to be already at the (xB,yB) + double t = Math.Tan(0.5 * dEta); double alpha = Math.Sin(dEta) * (Math.Sqrt(4 + 3 * t * t) - 1) / 3; @@ -1012,7 +1024,7 @@ namespace Avalonia.RenderHelpers /// Ellipse theta (angle measured from the abscissa) /// Large Arc Indicator /// Clockwise direction flag - public static void BuildArc(IStreamGeometryContextImpl path, Point p1, Point p2, Size size, double theta, bool isLargeArc, bool clockwise) + public static void BuildArc(StreamGeometryContext path, Point p1, Point p2, Size size, double theta, bool isLargeArc, bool clockwise) { // var orthogonalizer = new RotateTransform(-theta); @@ -1058,7 +1070,7 @@ namespace Avalonia.RenderHelpers } - double multiplier = Math.Sqrt(numerator / denominator); + double multiplier = Math.Sqrt(Math.Abs(numerator / denominator)); Point mulVec = new Point(rx * p1S.Y / ry, -ry * p1S.X / rx); int sign = (clockwise != isLargeArc) ? 1 : -1; @@ -1104,9 +1116,16 @@ namespace Avalonia.RenderHelpers // path.LineTo(c, true, true); // path.LineTo(clockwise ? p1 : p2, true,true); - path.LineTo(clockwise ? p1 : p2); var arc = new EllipticalArc(c.X, c.Y, rx, ry, theta, thetaStart, thetaEnd, false); + + double ManhattanDistance(Point p1, Point p2) => Math.Abs(p1.X - p2.X) + Math.Abs(p1.Y - p2.Y); + if (ManhattanDistance(p2, new Point(arc.X2, arc.Y2)) > ManhattanDistance(p2, new Point(arc.X1, arc.Y1))) + { + arc.DrawInOppositeDirection = true; + } + arc.BuildArc(path, arc._maxDegree, arc._defaultFlatness, false); + //path.LineTo(p2); //uncomment this to draw a pie //path.LineTo(c, true, true); @@ -1136,9 +1155,9 @@ namespace Avalonia.RenderHelpers } } - public static void ArcTo(IStreamGeometryContextImpl streamGeometryContextImpl, Point currentPoint, Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) + public static void ArcTo(StreamGeometryContext streamGeometryContextImpl, Point currentPoint, Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) { - EllipticalArc.BuildArc(streamGeometryContextImpl, currentPoint, point, size, rotationAngle*Math.PI/180, + EllipticalArc.BuildArc(streamGeometryContextImpl, currentPoint, point, size, rotationAngle*(Math.PI/180), isLargeArc, sweepDirection == SweepDirection.Clockwise); } diff --git a/src/Avalonia.Visuals/Media/StreamGeometryContext.cs b/src/Avalonia.Visuals/Media/StreamGeometryContext.cs index 0bfd774c79..88aba8365e 100644 --- a/src/Avalonia.Visuals/Media/StreamGeometryContext.cs +++ b/src/Avalonia.Visuals/Media/StreamGeometryContext.cs @@ -15,6 +15,8 @@ namespace Avalonia.Media { private readonly IStreamGeometryContextImpl _impl; + private Point _currentPoint; + /// /// Initializes a new instance of the class. /// @@ -47,6 +49,24 @@ namespace Avalonia.Media public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) { _impl.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection); + _currentPoint = point; + } + + + /// + /// Draws an arc to the specified point using polylines, quadratic or cubic Bezier curves + /// Significantly more precise when drawing elliptic arcs with extreme width:height ratios. + /// + /// The destination point. + /// The radii of an oval whose perimeter is used to draw the angle. + /// The rotation angle of the oval that specifies the curve. + /// true to draw the arc greater than 180 degrees; otherwise, false. + /// + /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. + /// + public void PreciseArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) + { + PreciseEllipticArcHelper.ArcTo(this, _currentPoint, point, size, rotationAngle, isLargeArc, sweepDirection); } /// @@ -57,6 +77,7 @@ namespace Avalonia.Media public void BeginFigure(Point startPoint, bool isFilled) { _impl.BeginFigure(startPoint, isFilled); + _currentPoint = startPoint; } /// @@ -68,6 +89,7 @@ namespace Avalonia.Media public void CubicBezierTo(Point point1, Point point2, Point point3) { _impl.CubicBezierTo(point1, point2, point3); + _currentPoint = point3; } /// @@ -78,6 +100,7 @@ namespace Avalonia.Media public void QuadraticBezierTo(Point control, Point endPoint) { _impl.QuadraticBezierTo(control, endPoint); + _currentPoint = endPoint; } /// @@ -87,6 +110,7 @@ namespace Avalonia.Media public void LineTo(Point point) { _impl.LineTo(point); + _currentPoint = point; } /// diff --git a/src/Shared/RenderHelpers/RenderHelpers.projitems b/src/Shared/RenderHelpers/RenderHelpers.projitems index c088097a9f..4c80ec50c4 100644 --- a/src/Shared/RenderHelpers/RenderHelpers.projitems +++ b/src/Shared/RenderHelpers/RenderHelpers.projitems @@ -9,7 +9,6 @@ Avalonia.RenderHelpers - \ No newline at end of file diff --git a/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs b/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs new file mode 100644 index 0000000000..fc9cbf6a7f --- /dev/null +++ b/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Controls.Shapes; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Xunit; + +#if AVALONIA_SKIA +namespace Avalonia.Skia.RenderTests +#else +namespace Avalonia.Direct2D1.RenderTests.Media +#endif +{ + public class StreamGeometryTests : TestBase + { + public StreamGeometryTests() + : base(@"Media\StreamGeometry") + { + } + + [Fact] + public async Task PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions() + { + var grid = new Avalonia.Controls.Primitives.UniformGrid() { Columns = 2, Rows = 4, Width = 320, Height = 400 }; + foreach (var sweepDirection in new[] { SweepDirection.Clockwise, SweepDirection.CounterClockwise }) + foreach (var isLargeArc in new[] { false, true }) + foreach (var isPrecise in new[] { false, true }) + { + Point Pt(double x, double y) => new Point(x, y); + Size Sz(double w, double h) => new Size(w, h); + var streamGeometry = new StreamGeometry(); + using (var context = streamGeometry.Open()) + { + context.BeginFigure(Pt(20, 20), true); + + if(isPrecise) + context.PreciseArcTo(Pt(40, 40), Sz(20, 20), 0, isLargeArc, sweepDirection); + else + context.ArcTo(Pt(40, 40), Sz(20, 20), 0, isLargeArc, sweepDirection); + context.LineTo(Pt(40, 20)); + context.LineTo(Pt(20, 20)); + context.EndFigure(true); + } + var pathShape = new Avalonia.Controls.Shapes.Path(); + pathShape.Data = streamGeometry; + pathShape.Stroke = new SolidColorBrush(Colors.CornflowerBlue); + pathShape.Fill = new SolidColorBrush(Colors.Gold); + pathShape.StrokeThickness = 2; + pathShape.Margin = new Thickness(20); + grid.Children.Add(pathShape); + } + await RenderToFile(grid); + } + } +} diff --git a/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png b/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..825b1d7ea7d2d1356f2798c162fed7572f8eb27b GIT binary patch literal 6332 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 H