#1,150 – Custom Arc Shape, part II
September 3, 2014 1 Comment
Below is code that implements a custom Shape to draw an arc. The earlier code has been improved to:
- Support elliptical arcs (height != width)
- Add dependency properties for start and end angles
Start and end angles are automatically coerced to keep them within the range [0, 360).
public class Arc : Shape { // Angle that arc starts at public double StartAngle { get { return (double)GetValue(StartAngleProperty); } set { SetValue(StartAngleProperty, value); } } // DependencyProperty - StartAngle private static PropertyMetadata startAngleMetadata = new PropertyMetadata( 0.0, // Default value null, // Property changed callback new CoerceValueCallback(CoerceAngle)); // Coerce value callback public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), startAngleMetadata); // Angle that arc ends at public double EndAngle { get { return (double)GetValue(EndAngleProperty); } set { SetValue(EndAngleProperty, value); } } // DependencyProperty - EndAngle private static PropertyMetadata endAngleMetadata = new PropertyMetadata( 90.0, // Default value null, // Property changed callback new CoerceValueCallback(CoerceAngle)); // Coerce value callback public static readonly DependencyProperty EndAngleProperty = DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), endAngleMetadata); private static object CoerceAngle(DependencyObject depObj, object baseVal) { double angle = (double)baseVal; angle = Math.Min(angle, 359.9); angle = Math.Max(angle, 0.0); return angle; } protected override Geometry DefiningGeometry { get { double maxWidth = RenderSize.Width; double maxHeight = RenderSize.Height; double xStart = maxWidth / 2.0 * Math.Cos(StartAngle * Math.PI / 180.0); double yStart = maxHeight / 2.0 * Math.Sin(StartAngle * Math.PI / 180.0); double xEnd = maxWidth / 2.0 * Math.Cos(EndAngle * Math.PI / 180.0); double yEnd = maxHeight / 2.0 * Math.Sin(EndAngle * Math.PI / 180.0); StreamGeometry geom = new StreamGeometry(); using (StreamGeometryContext ctx = geom.Open()) { ctx.BeginFigure( new Point((maxWidth / 2.0) + xStart, (maxHeight / 2.0) - yStart), false, false); ctx.ArcTo( new Point((maxWidth / 2.0) + xEnd, (maxHeight / 2.0) - yEnd), new Size(maxWidth / 2.0, maxHeight / 2), 0.0, // rotationAngle (EndAngle - StartAngle) > 180, // greater than 180 deg? SweepDirection.Counterclockwise, true, // isStroked true); } return geom; } } }
We can use the Arc shape as shown below.