none
Drawing pie slices

    Question

  • Back in the GDI days it was easy to draw an arc depicting a pie slice of any radius. I've been struggling for a while now to do it in WPF. What is the best way to do it? I'd prefer not to do it in xaml, but rather in code to give me more control over it.

    I've been playing with ArcSegments, and I can get one half of the pie to draw, but as soon as the radius goes over 180 degrees (yes, I'm setting IsLargArc to true), it loses its circular shape. It seems to reach the 180 degree mark and goes straight to the ArcSegment's Point without caring about retaining its radius.

    Can anyone offer an insight?
    Thursday, April 17, 2008 12:41 PM

Answers

  • This is XAML but it's similar to how you'd do it in code.  This is actually a standalone XAML file that animates a pie slice from 0 through 360 degrees and back again.  Maybe it'll help you figure out what you're doing wrong.

     

     

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Path Stroke="Red" StrokeThickness="3" Fill="Yellow">
            <Path.Data>
                <PathGeometry>
                    <PathFigure StartPoint="200 200" IsClosed="True">
                        <LineSegment Point="200 100" />
                        <ArcSegment x:Name="arc"
                                    Size="100 100"
                                    SweepDirection="Clockwise" />
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
        </Path>

        <Page.Triggers>
            <EventTrigger RoutedEvent="Page.Loaded">
                <BeginStoryboard>
                    <Storyboard RepeatBehavior="Forever"
                                AutoReverse="True">
                        <PointAnimationUsingPath
                                Storyboard.TargetName="arc"
                                Storyboard.TargetProperty="Point"
                                Duration="0:0:5">
                            <PointAnimationUsingPath.PathGeometry>
                                <PathGeometry>
                                    <PathFigure StartPoint="200 100">
                                        <ArcSegment Size="100 100" Point="200 300"
                                                    SweepDirection="ClockWise" />
                                        <ArcSegment Size="100 100" Point="200 100"
                                                    SweepDirection="Clockwise" />
                                    </PathFigure>
                                </PathGeometry>
                            </PointAnimationUsingPath.PathGeometry>
                        </PointAnimationUsingPath>

                        <BooleanAnimationUsingKeyFrames
                                Storyboard.TargetName="arc"
                                Storyboard.TargetProperty="IsLargeArc">
                            <DiscreteBooleanKeyFrame KeyTime="0:0:2.5" Value="True" />
                            <DiscreteBooleanKeyFrame KeyTime="0:0:5" Value="False" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Page.Triggers>
    </Page>

    Thursday, April 17, 2008 11:45 PM
  • Thank you both for your responses. I didn't post code because I wasn't asking how to solve the problem with my implementation so much as I was asking what the best approach would be, but I did in fact solve my problem. Here is the code for anyone that has similar needs:

     

    Code Snippet
    Path path = new Path();

     

    Canvas.SetLeft(path, canvas.ActualWidth / 2);

    Canvas.SetTop(path, canvas.ActualHeight / 2);

     

    path.Fill = Brushes.Red;

    path.Stroke = Brushes.Red;

     

    PathGeometry pathGeometry = new PathGeometry();

     

    PathFigure pathFigure = new PathFigure();

    pathFigure.StartPoint = new Point(0, 0);

    pathFigure.IsClosed = true;

     

    Double radius = 50.0;

    Double angle = 45.0;

     

    // Starting Point

    LineSegment lineSegment = new LineSegment(new Point(radius, 0), true);

     

    // Arc

    ArcSegment arcSegment = new ArcSegment();

    arcSegment.IsLargeArc = angle >= 180.0;

    arcSegment.Point = new Point(Math.Cos(angle * Math.PI / 180) * radius, Math.Sin(angle * Math.PI / 180) * radius);

    arcSegment.Size = new Size(radius, radius);

    arcSegment.SweepDirection = SweepDirection.Clockwise;

     

    pathFigure.Segments.Add(lineSegment);

    pathFigure.Segments.Add(arcSegment);

     

    pathGeometry.Figures.Add(pathFigure);

     

    path.Data = pathGeometry;

     

    canvas.Children.Add(path);

     

     

    This will work for any angle 0-359 (359 draws the full circle), but it only works if you start at 1,0 (0/2pi on a unit circle). I'd like it to start at 1,0 (pi/2), but I haven't really put any time in on it. I'll post if I figure it out. I'd like to avoid doing a rotation, however.
    Friday, April 25, 2008 9:08 PM

All replies

  • Can you post some code demonstrating the issue you are having? This would be very difficult to troubleshoot without seeing the code.

     

    Keith

     

    Thursday, April 17, 2008 8:57 PM
  • This is XAML but it's similar to how you'd do it in code.  This is actually a standalone XAML file that animates a pie slice from 0 through 360 degrees and back again.  Maybe it'll help you figure out what you're doing wrong.

     

     

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Path Stroke="Red" StrokeThickness="3" Fill="Yellow">
            <Path.Data>
                <PathGeometry>
                    <PathFigure StartPoint="200 200" IsClosed="True">
                        <LineSegment Point="200 100" />
                        <ArcSegment x:Name="arc"
                                    Size="100 100"
                                    SweepDirection="Clockwise" />
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
        </Path>

        <Page.Triggers>
            <EventTrigger RoutedEvent="Page.Loaded">
                <BeginStoryboard>
                    <Storyboard RepeatBehavior="Forever"
                                AutoReverse="True">
                        <PointAnimationUsingPath
                                Storyboard.TargetName="arc"
                                Storyboard.TargetProperty="Point"
                                Duration="0:0:5">
                            <PointAnimationUsingPath.PathGeometry>
                                <PathGeometry>
                                    <PathFigure StartPoint="200 100">
                                        <ArcSegment Size="100 100" Point="200 300"
                                                    SweepDirection="ClockWise" />
                                        <ArcSegment Size="100 100" Point="200 100"
                                                    SweepDirection="Clockwise" />
                                    </PathFigure>
                                </PathGeometry>
                            </PointAnimationUsingPath.PathGeometry>
                        </PointAnimationUsingPath>

                        <BooleanAnimationUsingKeyFrames
                                Storyboard.TargetName="arc"
                                Storyboard.TargetProperty="IsLargeArc">
                            <DiscreteBooleanKeyFrame KeyTime="0:0:2.5" Value="True" />
                            <DiscreteBooleanKeyFrame KeyTime="0:0:5" Value="False" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Page.Triggers>
    </Page>

    Thursday, April 17, 2008 11:45 PM
  • Thank you both for your responses. I didn't post code because I wasn't asking how to solve the problem with my implementation so much as I was asking what the best approach would be, but I did in fact solve my problem. Here is the code for anyone that has similar needs:

     

    Code Snippet
    Path path = new Path();

     

    Canvas.SetLeft(path, canvas.ActualWidth / 2);

    Canvas.SetTop(path, canvas.ActualHeight / 2);

     

    path.Fill = Brushes.Red;

    path.Stroke = Brushes.Red;

     

    PathGeometry pathGeometry = new PathGeometry();

     

    PathFigure pathFigure = new PathFigure();

    pathFigure.StartPoint = new Point(0, 0);

    pathFigure.IsClosed = true;

     

    Double radius = 50.0;

    Double angle = 45.0;

     

    // Starting Point

    LineSegment lineSegment = new LineSegment(new Point(radius, 0), true);

     

    // Arc

    ArcSegment arcSegment = new ArcSegment();

    arcSegment.IsLargeArc = angle >= 180.0;

    arcSegment.Point = new Point(Math.Cos(angle * Math.PI / 180) * radius, Math.Sin(angle * Math.PI / 180) * radius);

    arcSegment.Size = new Size(radius, radius);

    arcSegment.SweepDirection = SweepDirection.Clockwise;

     

    pathFigure.Segments.Add(lineSegment);

    pathFigure.Segments.Add(arcSegment);

     

    pathGeometry.Figures.Add(pathFigure);

     

    path.Data = pathGeometry;

     

    canvas.Children.Add(path);

     

     

    This will work for any angle 0-359 (359 draws the full circle), but it only works if you start at 1,0 (0/2pi on a unit circle). I'd like it to start at 1,0 (pi/2), but I haven't really put any time in on it. I'll post if I figure it out. I'd like to avoid doing a rotation, however.
    Friday, April 25, 2008 9:08 PM
  • Thanks for the code.
    Thursday, July 08, 2010 10:05 AM