diff --git a/src/Avalonia.Controls/Shapes/Arc.cs b/src/Avalonia.Controls/Shapes/Arc.cs index 5ebb321f9b..de3814f215 100644 --- a/src/Avalonia.Controls/Shapes/Arc.cs +++ b/src/Avalonia.Controls/Shapes/Arc.cs @@ -1,8 +1,12 @@ using System; using Avalonia.Media; +using Avalonia.Utilities; namespace Avalonia.Controls.Shapes { + /// + /// Represents a circular or elliptical arc (a segment of a curve). + /// public class Arc : Shape { /// @@ -19,8 +23,12 @@ namespace Avalonia.Controls.Shapes static Arc() { - StrokeThicknessProperty.OverrideDefaultValue(1); - AffectsGeometry(BoundsProperty, StrokeThicknessProperty, StartAngleProperty, SweepAngleProperty); + StrokeThicknessProperty.OverrideDefaultValue(1.0d); + AffectsGeometry( + BoundsProperty, + StrokeThicknessProperty, + StartAngleProperty, + SweepAngleProperty); } /// @@ -42,10 +50,11 @@ namespace Avalonia.Controls.Shapes set => SetValue(SweepAngleProperty, value); } + /// protected override Geometry CreateDefiningGeometry() { - var angle1 = DegreesToRad(StartAngle); - var angle2 = angle1 + DegreesToRad(SweepAngle); + var angle1 = MathUtilities.Deg2Rad(StartAngle); + var angle2 = angle1 + MathUtilities.Deg2Rad(SweepAngle); var startAngle = Math.Min(angle1, angle2); var sweepAngle = Math.Max(angle1, angle2); @@ -80,24 +89,25 @@ namespace Avalonia.Controls.Shapes var arcGeometry = new StreamGeometry(); - using (var ctx = arcGeometry.Open()) + using (StreamGeometryContext context = arcGeometry.Open()) { - ctx.BeginFigure(startPoint, false); - ctx.ArcTo(endPoint, new Size(radiusX, radiusY), angleGap, angleGap >= Math.PI, + context.BeginFigure(startPoint, false); + context.ArcTo( + endPoint, + new Size(radiusX, radiusY), + rotationAngle: angleGap, + isLargeArc: angleGap >= Math.PI, SweepDirection.Clockwise); - ctx.EndFigure(false); + context.EndFigure(false); } return arcGeometry; } } - static double DegreesToRad(double inAngle) => - inAngle * Math.PI / 180; + private static double RadToNormRad(double inAngle) => ((inAngle % (Math.PI * 2)) + (Math.PI * 2)) % (Math.PI * 2); - static double RadToNormRad(double inAngle) => ((inAngle % (Math.PI * 2)) + (Math.PI * 2)) % (Math.PI * 2); - - static Point GetRingPoint(double radiusX, double radiusY, double centerX, double centerY, double angle) => + private 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); } } diff --git a/src/Avalonia.Controls/Shapes/Sector.cs b/src/Avalonia.Controls/Shapes/Sector.cs index 5d2f6701a7..a9b7e8939b 100644 --- a/src/Avalonia.Controls/Shapes/Sector.cs +++ b/src/Avalonia.Controls/Shapes/Sector.cs @@ -4,45 +4,71 @@ using Avalonia.Utilities; namespace Avalonia.Controls.Shapes { + /// + /// Represents a circular or elliptical sector (a pie-shaped closed region of a circle or ellipse). + /// public class Sector : Shape { - public static readonly StyledProperty StartAngleProperty = AvaloniaProperty.Register(nameof(StartAngle), 0.0d); - public static readonly StyledProperty AngleProperty = AvaloniaProperty.Register(nameof(Angle), 0.0d); + /// + /// Defines the property. + /// + public static readonly StyledProperty StartAngleProperty = + AvaloniaProperty.Register(nameof(StartAngle), 0.0d); + /// + /// Defines the property. + /// + public static readonly StyledProperty SweepAngleProperty = + AvaloniaProperty.Register(nameof(SweepAngle), 0.0d); + + /// + /// Gets or sets the angle at which the sector's arc starts, in degrees. + /// public double StartAngle { get => GetValue(StartAngleProperty); set => SetValue(StartAngleProperty, value); } - public double Angle + /// + /// Gets or sets the angle, in degrees, added to the defining where the sector's arc ends. + /// A positive value is clockwise, negative is counter-clockwise. + /// + public double SweepAngle { - get => GetValue(AngleProperty); - set => SetValue(AngleProperty, value); + get => GetValue(SweepAngleProperty); + set => SetValue(SweepAngleProperty, value); } static Sector() { StrokeThicknessProperty.OverrideDefaultValue(1.0d); - AffectsGeometry(BoundsProperty, StrokeThicknessProperty, StartAngleProperty, AngleProperty); + AffectsGeometry( + BoundsProperty, + StrokeThicknessProperty, + StartAngleProperty, + SweepAngleProperty); } + /// protected override Geometry? CreateDefiningGeometry() { Rect rect = new Rect(Bounds.Size); Rect deflatedRect = rect.Deflate(StrokeThickness * 0.5d); - if (Angle >= 360.0d || Angle <= -360.0d) + if (SweepAngle >= 360.0d || SweepAngle <= -360.0d) { return new EllipseGeometry(deflatedRect); } - if (Angle == 0.0d) + if (SweepAngle == 0.0d) { return new StreamGeometry(); } - (double startAngle, double endAngle) = MathUtilities.GetMinMaxFromDelta(MathUtilities.Deg2Rad(StartAngle), MathUtilities.Deg2Rad(Angle)); + (double startAngle, double endAngle) = MathUtilities.GetMinMaxFromDelta( + MathUtilities.Deg2Rad(StartAngle), + MathUtilities.Deg2Rad(SweepAngle)); Point centre = new Point(rect.Width * 0.5d, rect.Height * 0.5d); double radiusX = deflatedRect.Width * 0.5d; @@ -51,13 +77,19 @@ namespace Avalonia.Controls.Shapes Point endCurvePoint = MathUtilities.GetEllipsePoint(centre, radiusX, radiusY, endAngle); Size size = new Size(radiusX, radiusY); - StreamGeometry streamGeometry = new StreamGeometry(); - using StreamGeometryContext streamGeometryContext = streamGeometry.Open(); - - streamGeometryContext.BeginFigure(startCurvePoint, false); - streamGeometryContext.ArcTo(endCurvePoint, size, 0.0d, Math.Abs(Angle) > 180.0d, SweepDirection.Clockwise); - streamGeometryContext.LineTo(centre); - streamGeometryContext.EndFigure(true); + var streamGeometry = new StreamGeometry(); + using (StreamGeometryContext context = streamGeometry.Open()) + { + context.BeginFigure(startCurvePoint, false); + context.ArcTo( + endCurvePoint, + size, + rotationAngle: 0.0d, + isLargeArc: Math.Abs(SweepAngle) > 180.0d, + SweepDirection.Clockwise); + context.LineTo(centre); + context.EndFigure(true); + } return streamGeometry; }