Browse Source

Merge pull request #8667 from ErrorCraft/feature/sector-shape

Add Sector shape
pull/8749/head
Max Katz 4 years ago
committed by GitHub
parent
commit
ee3060543e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      src/Avalonia.Base/Utilities/MathUtilities.cs
  2. 65
      src/Avalonia.Controls/Shapes/Sector.cs

35
src/Avalonia.Base/Utilities/MathUtilities.cs

@ -324,6 +324,41 @@ namespace Avalonia.Utilities
return angle * 2 * Math.PI;
}
/// <summary>
/// Calculates the point of an angle on an ellipse.
/// </summary>
/// <param name="centre">The centre point of the ellipse.</param>
/// <param name="radiusX">The x radius of the ellipse.</param>
/// <param name="radiusY">The y radius of the ellipse.</param>
/// <param name="angle">The angle in radians.</param>
/// <returns>A point on the ellipse.</returns>
public static Point GetEllipsePoint(Point centre, double radiusX, double radiusY, double angle)
{
return new Point(radiusX * Math.Cos(angle) + centre.X, radiusY * Math.Sin(angle) + centre.Y);
}
/// <summary>
/// Gets the minimum and maximum from the specified numbers.
/// </summary>
/// <param name="a">The first number.</param>
/// <param name="b">The second number.</param>
/// <returns>A tuple containing the minimum and maximum of the two specified numbers.</returns>
public static (double min, double max) GetMinMax(double a, double b)
{
return a < b ? (a, b) : (b, a);
}
/// <summary>
/// Gets the minimum and maximum from the specified number and the difference with that number.
/// </summary>
/// <param name="initialValue">The initial value to use.</param>
/// <param name="delta">The difference for <paramref name="initialValue"/>.</param>
/// <returns>A tuple containing the minimum and maximum of the specified number and the difference with that number.</returns>
public static (double min, double max) GetMinMaxFromDelta(double initialValue, double delta)
{
return GetMinMax(initialValue, initialValue + delta);
}
private static void ThrowCannotBeGreaterThanException<T>(T min, T max)
{
throw new ArgumentException($"{min} cannot be greater than {max}.");

65
src/Avalonia.Controls/Shapes/Sector.cs

@ -0,0 +1,65 @@
using System;
using Avalonia.Media;
using Avalonia.Utilities;
namespace Avalonia.Controls.Shapes
{
public class Sector : Shape
{
public static readonly StyledProperty<double> StartAngleProperty = AvaloniaProperty.Register<Sector, double>(nameof(StartAngle), 0.0d);
public static readonly StyledProperty<double> AngleProperty = AvaloniaProperty.Register<Sector, double>(nameof(Angle), 0.0d);
public double StartAngle
{
get => GetValue(StartAngleProperty);
set => SetValue(StartAngleProperty, value);
}
public double Angle
{
get => GetValue(AngleProperty);
set => SetValue(AngleProperty, value);
}
static Sector()
{
StrokeThicknessProperty.OverrideDefaultValue<Sector>(1.0d);
AffectsGeometry<Sector>(BoundsProperty, StrokeThicknessProperty, StartAngleProperty, AngleProperty);
}
protected override Geometry? CreateDefiningGeometry()
{
Rect rect = new Rect(Bounds.Size);
Rect deflatedRect = rect.Deflate(StrokeThickness * 0.5d);
if (Angle >= 360.0d || Angle <= -360.0d)
{
return new EllipseGeometry(deflatedRect);
}
if (Angle == 0.0d)
{
return new StreamGeometry();
}
(double startAngle, double endAngle) = MathUtilities.GetMinMaxFromDelta(MathUtilities.Deg2Rad(StartAngle), MathUtilities.Deg2Rad(Angle));
Point centre = new Point(rect.Width * 0.5d, rect.Height * 0.5d);
double radiusX = deflatedRect.Width * 0.5d;
double radiusY = deflatedRect.Height * 0.5d;
Point startCurvePoint = MathUtilities.GetEllipsePoint(centre, radiusX, radiusY, startAngle);
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);
return streamGeometry;
}
}
}
Loading…
Cancel
Save