See the question and my original answer on StackOverflow

WPF has lots of algorithms builtin that can avoid writing complex ones for lazy guys like me. When used properly, the Geometry class is capable of doing many things, with good performance. So you really want to start using geometries instead of collections of points, or shapes (which are more UI utilities).

Here, I simply use the combination feature of geometry, for a 4 lines-of-code algorithm:

public static IEnumerable<Rect> ComputeIntersectingSegments(Geometry geometry, double y, double width)
    // Add a geometry line to compute intersections.
    // A geometry must not be 0 thickness for combination to be meaningful.
    // So we widen the line by a very small size
    var line = new LineGeometry(new Point(0, y), new Point(width, y)).GetWidenedPathGeometry(new Pen(null, 0.01));

    // Intersect the line with input geometry and compute intersections
    var combined = Geometry.Combine(line, geometry, GeometryCombineMode.Intersect, null);
    foreach (var figure in combined.Figures)
        // the resulting figure can be a complex thing
        // we just want the bounding box
        yield return new PathGeometry(new PathFigure[] { figure }).Bounds;

public partial class MainWindow : Window
    public MainWindow()

        // use a canvas to display shape and intersections
        var canvas = new Canvas();
        Content = canvas;

        // your polygon can be built as a geometry for example like this:
        // var myPolygon = Geometry.Parse("M50,50 L50,165 L140,165 L140,120 L70,120 L80,70 L140,70 L140,50");

        // build a 'o' shape for testing, add it to the canvas
        var circle1 = new EllipseGeometry(new Point(100, 100), 70, 70);
        var circle2 = new EllipseGeometry(new Point(100, 100), 40, 40);

        // exclude mode will compute the 'o' shape ...
        var oGeometry = new CombinedGeometry(GeometryCombineMode.Exclude, circle1, circle2);

        var oPath = new Path();
        oPath.Stroke = Brushes.Black;
        oPath.Fill = Brushes.LightSeaGreen;
        oPath.StrokeThickness = 2;
        oPath.Data = oGeometry;


        // test many heights
        for (int y = 0; y < Height; y += 25)
            foreach (var segment in ComputeIntersectingSegments(oGeometry, y, Width))
                // for our sample, we add each segment to the canvas
                // Height is irrelevant, we use 2 for tests
                var line = new Rectangle();
                Canvas.SetLeft(line, segment.X);
                Canvas.SetTop(line, segment.Y);
                line.Width = segment.Width;
                line.Height = 2;
                line.Stroke = Brushes.Red;
                line.StrokeThickness = 1;

This is the result:

enter image description here