From 82d2ee175f39f044b6cc7864899167eafb4712c9 Mon Sep 17 00:00:00 2001 From: Splitwirez Date: Sat, 19 Jun 2021 15:36:58 -0400 Subject: [PATCH] Add `Arc`...again... --- src/Avalonia.Controls/Shapes/Arc.cs | 99 +++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/Avalonia.Controls/Shapes/Arc.cs diff --git a/src/Avalonia.Controls/Shapes/Arc.cs b/src/Avalonia.Controls/Shapes/Arc.cs new file mode 100644 index 0000000000..f6738e10f2 --- /dev/null +++ b/src/Avalonia.Controls/Shapes/Arc.cs @@ -0,0 +1,99 @@ +using System; +using Avalonia.Media; + +namespace Avalonia.Controls.Shapes +{ + public class Arc : Shape + { + /// + /// Defines the property. + /// + public static readonly StyledProperty StartAngleProperty = + AvaloniaProperty.Register(nameof(StartAngle), 0.0); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SweepAngleProperty = + AvaloniaProperty.Register(nameof(SweepAngle), 0.0); + + static Arc() + { + StrokeThicknessProperty.OverrideDefaultValue(1); + AffectsGeometry(BoundsProperty, StrokeThicknessProperty, StartAngleProperty, SweepAngleProperty); + } + + /// + /// Gets or sets the angle at which the arc starts, in degrees. + /// + public double StartAngle + { + get { return GetValue(StartAngleProperty); } + set { SetValue(StartAngleProperty, value); } + } + + /// + /// Gets or sets the angle at which the arc ends relative to the start angle, in degrees. + /// + public double SweepAngle + { + get { return GetValue(SweepAngleProperty); } + set { SetValue(SweepAngleProperty, value); } + } + + protected override Geometry CreateDefiningGeometry() + { + double angle1 = DegreesToRad(StartAngle); + double angle2 = angle1 + DegreesToRad(SweepAngle); + + double startAngle = Math.Min(angle1, angle2); + double sweepAngle = Math.Max(angle1, angle2); + + double normStart = RadToNormRad(startAngle); + double normEnd = RadToNormRad(sweepAngle); + + var rect = new Rect(Bounds.Size); + + if ((normStart == normEnd) && (startAngle != sweepAngle)) //complete ring + { + return new EllipseGeometry(rect.Deflate(StrokeThickness / 2)); + } + else if (SweepAngle == 0) + { + return new StreamGeometry(); + } + else //partial arc + { + var deflatedRect = rect.Deflate(StrokeThickness / 2); + + double centerX = rect.Center.X; + double centerY = rect.Center.Y; + + double radiusX = deflatedRect.Width / 2; + double radiusY = deflatedRect.Height / 2; + + double angleGap = RadToNormRad(sweepAngle - startAngle); + + Point startPoint = GetRingPoint(radiusX, radiusY, centerX, centerY, startAngle); + Point endPoint = GetRingPoint(radiusX, radiusY, centerX, centerY, sweepAngle); + + StreamGeometry arcGeometry = new StreamGeometry(); + using (var ctx = arcGeometry.Open()) + { + ctx.BeginFigure(startPoint, false); + ctx.ArcTo(endPoint, new Size(radiusX, radiusY), angleGap, angleGap >= Math.PI, SweepDirection.Clockwise); + ctx.EndFigure(false); + } + return arcGeometry; + } + } + + static double DegreesToRad(double inAngle) => + inAngle * Math.PI / 180; + + static double RadToNormRad(double inAngle) => (0 + (inAngle % (Math.PI * 2)) + (Math.PI * 2)) % (Math.PI * 2); + + static Point GetRingPoint(double radiusX, double radiusY, double centerX, double centerY, double angle) => + new Point((radiusX * Math.Cos(angle)) + centerX, (radiusY * Math.Sin(angle)) + centerY); + } +}