C#
point in polygon
computational geometry
programming
algorithms

C Point in polygon

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

The point-in-polygon problem asks whether a 2D point lies inside, outside, or exactly on the boundary of a polygon. In C#, the most practical general-purpose solution is usually the ray-casting test, with an explicit boundary check added so edge cases do not get misclassified.

The Core Idea Behind Ray Casting

Imagine shooting a horizontal ray to the right from the test point. Count how many times that ray crosses polygon edges.

  • an odd number of crossings means the point is inside
  • an even number means the point is outside

This works for simple polygons because every time the ray crosses the boundary, it toggles between inside and outside.

A Runnable C# Implementation

The following example uses a small Point2D struct and a ray-casting function. It also checks whether the point lies exactly on an edge.

csharp
1using System;
2
3public readonly record struct Point2D(double X, double Y);
4
5public static class Geometry
6{
7    public static bool IsPointInPolygon(Point2D point, Point2D[] polygon)
8    {
9        bool inside = false;
10
11        for (int i = 0, j = polygon.Length - 1; i < polygon.Length; j = i++)
12        {
13            Point2D a = polygon[i];
14            Point2D b = polygon[j];
15
16            if (IsPointOnSegment(point, a, b))
17            {
18                return true;
19            }
20
21            bool intersects = ((a.Y > point.Y) != (b.Y > point.Y)) &&
22                              (point.X < (b.X - a.X) * (point.Y - a.Y) / (b.Y - a.Y) + a.X);
23
24            if (intersects)
25            {
26                inside = !inside;
27            }
28        }
29
30        return inside;
31    }
32
33    private static bool IsPointOnSegment(Point2D p, Point2D a, Point2D b)
34    {
35        double cross = (p.Y - a.Y) * (b.X - a.X) - (p.X - a.X) * (b.Y - a.Y);
36        if (Math.Abs(cross) > 1e-9)
37        {
38            return false;
39        }
40
41        double dot = (p.X - a.X) * (b.X - a.X) + (p.Y - a.Y) * (b.Y - a.Y);
42        if (dot < 0)
43        {
44            return false;
45        }
46
47        double squaredLength = (b.X - a.X) * (b.X - a.X) + (b.Y - a.Y) * (b.Y - a.Y);
48        return dot <= squaredLength;
49    }
50}
51
52public class Program
53{
54    public static void Main()
55    {
56        Point2D[] polygon =
57        {
58            new(0, 0),
59            new(5, 0),
60            new(5, 5),
61            new(0, 5)
62        };
63
64        Console.WriteLine(Geometry.IsPointInPolygon(new Point2D(2, 2), polygon));
65        Console.WriteLine(Geometry.IsPointInPolygon(new Point2D(6, 2), polygon));
66        Console.WriteLine(Geometry.IsPointInPolygon(new Point2D(5, 3), polygon));
67    }
68}

This prints True, False, and True. The last result counts a boundary point as inside because the code explicitly checks edges first.

Why The Boundary Check Matters

A plain ray-casting implementation often produces inconsistent answers for points that sit exactly on an edge or vertex. That is not a flaw in the idea of ray casting; it is a sign that the implementation skipped a policy decision.

In real programs, choose one rule and document it:

  • boundary counts as inside
  • boundary counts as outside
  • boundary is a separate result

The example above treats boundary as inside because that is often convenient in UI and GIS-style applications.

Handling Vertices Carefully

Vertices are where many buggy implementations fail. If the ray passes exactly through a polygon vertex, naïve code may count the crossing twice.

The condition used in the example:

csharp
((a.Y > point.Y) != (b.Y > point.Y))

helps avoid double counting by only considering edges that straddle the point's horizontal line in a controlled way. This is a standard trick in robust ray-casting implementations.

Concave Polygons Are Fine

Ray casting works for both convex and concave simple polygons. It does not require the polygon to be a rectangle or any other easy shape.

For example, this polygon is concave:

csharp
1Point2D[] polygon =
2{
3    new(0, 0),
4    new(4, 0),
5    new(4, 4),
6    new(2, 2),
7    new(0, 4)
8};

The same algorithm still works as long as the polygon is simple, meaning its edges do not cross each other.

When Winding Number Is Better

Another well-known approach is the winding-number algorithm. It tracks how many times the polygon winds around the point instead of just counting parity.

For ordinary inside-versus-outside checks, ray casting is simpler and usually enough. Winding number becomes attractive when:

  • you want a more geometric orientation-based formulation
  • you are working with polygons whose orientation matters
  • you want finer control over complex shape semantics

For many business applications, ray casting plus a clear boundary policy is the best balance of simplicity and correctness.

Common Pitfalls

  • Ignoring points that fall exactly on an edge or vertex.
  • Double counting intersections at polygon vertices.
  • Assuming the algorithm only works for convex polygons.
  • Feeding in self-intersecting polygons and expecting simple inside-outside semantics.
  • Comparing floating-point values with exact equality instead of using a tolerance.

Summary

  • In C#, ray casting is a practical solution to the point-in-polygon problem.
  • Count horizontal-ray crossings and add an explicit boundary check.
  • Concave polygons are fine as long as the polygon is simple.
  • Vertex handling is where many implementations go wrong.
  • Decide whether boundary points count as inside, outside, or separate, and code that policy explicitly.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.