The polygon is given as a list of Vector2I objects (2 dimensional, integer coordinates). How can i test if a given point is inside? All implementations i found on the web fail for some trivial counter-example. It really seems to be hard to write a correct implementation. The language does not matter as i will port it myself.
-
A comment. If it is an interview problem, you are expected to get a O(log n) solution because convex polygon is a special case. Use a binary search along with the idea given in ufukgun's answer. – Yin Zhu Mar 23 '10 at 09:45
-
5The answers here are surprisingly bad. [This article by Eric Haines](http://erich.realtimerendering.com/ptinpoly/) describes many methods for doing this, and also provides references to well known texts. – bobobobo Jun 18 '13 at 17:01
-
possible duplicate of [Point in Polygon aka hit test](http://stackoverflow.com/questions/217578/point-in-polygon-aka-hit-test) – bobobobo Jun 18 '13 at 17:40
9 Answers
If it is convex, a trivial way to check it is that the point is laying on the same side of all the segments (if traversed in the same order).
You can check that easily with the dot product (as it is proportional to the cosine of the angle formed between the segment and the point, if we calculate it with the normal of the edge, those with positive sign would lay on the right side and those with negative sign on the left side).
Here is the code in Python:
RIGHT = "RIGHT"
LEFT = "LEFT"
def inside_convex_polygon(point, vertices):
previous_side = None
n_vertices = len(vertices)
for n in xrange(n_vertices):
a, b = vertices[n], vertices[(n+1)%n_vertices]
affine_segment = v_sub(b, a)
affine_point = v_sub(point, a)
current_side = get_side(affine_segment, affine_point)
if current_side is None:
return False #outside or over an edge
elif previous_side is None: #first segment
previous_side = current_side
elif previous_side != current_side:
return False
return True
def get_side(a, b):
x = cosine_sign(a, b)
if x < 0:
return LEFT
elif x > 0:
return RIGHT
else:
return None
def v_sub(a, b):
return (a[0]-b[0], a[1]-b[1])
def cosine_sign(a, b):
return a[0]*b[1]-a[1]*b[0]

- 74,053
- 25
- 135
- 175
-
7Hacking something together when there are well known solutions will almost always miss some edge cases. – Eric Jul 14 '09 at 06:38
-
What happens for points on the edge? Say k = 0, it should give a ZeroDivisionError. – stefano Jan 07 '12 at 15:02
-
@stefano well, if that is a possible case then we'll have to decide if that means inside or outside (the boundary is open or closed) – fortran Jan 08 '12 at 12:08
-
@fortran true, but don't you think it would be opportune to make a test to check if k==0 before the division by abs(k), to avoid the error? – stefano Jan 08 '12 at 15:19
-
I realize this is an old post, but I found it quite useful! I would agree with @stefano however. Simply test `k == 0` and return true or false immediately (depending on what you decide the edge case means). In fact, I would remove the normalization of `k` altogether as well. Rather than keeping `sign` as `-1` or `1` and testing `k != sign` for the outside condition, simply test `k * sign < 0`. This is likely to perform better. – kqnr Jan 10 '12 at 21:30
-
@chomp stefano is right, but it is not as simple as an early return if k == 0. In order to return True, you must perform an additional check to see if the point is actually over the edge (it can be outside, but parallel to it, so the scalar product is still zero). – fortran Jan 11 '12 at 09:45
-
This doesn't work. print inside_convex_polygon((35.68333333, 139.75),[(90,0),(0,180),(0,-180)]) – jolly Feb 20 '18 at 02:25
-
1^ rendering of above polygon from @jolly : https://www.wolframalpha.com/input/?i=polygon+vertices+(90,0),(0,180),(0,-180) – Jonathan Feb 27 '19 at 12:16
-
@nielsen thanks for the correction, that was quite a blunder, I don't know what was I thinking – fortran Feb 03 '20 at 08:31
-
@jolly It returns `False`, and that point is outside, as you can see https://www.wolframalpha.com/input/?i=polygon+vertices+%2890%2C0%29%2C%280%2C180%29%2C%280%2C-180%29%3B+point+%2835.68333333%2C+139.75%29 – fortran Feb 03 '20 at 08:35
-
I would specify that the dot product is between the point and the perpendicular to the segment – giubacchio Apr 03 '21 at 06:59
-
@giubacchio you are correct, in the cosine_sign function one of the vectors is rotated 90º (swap indices and negate) – fortran Apr 09 '21 at 16:53
The Ray Casting or Winding methods are the most common for this problem. See the Wikipedia article for details.
Also, Check out this page for a well-documented solution in C.

- 116,942
- 41
- 177
- 214
-
For integer coordinates, wrf's code snippet will be more than sufficient. – Eric Jul 13 '09 at 14:13
-
1It's the most common... but if you already know the polygon is CONVEX, like this case, the fortran is supposed to be faster! – Wagner Patriota Aug 15 '13 at 18:42
-
1
If the polygon is convex, then in C#, the following implements the "test if always on same side" method, and runs at most at O(n of polygon points):
public static bool IsInConvexPolygon(Point testPoint, List<Point> polygon)
{
//Check if a triangle or higher n-gon
Debug.Assert(polygon.Length >= 3);
//n>2 Keep track of cross product sign changes
var pos = 0;
var neg = 0;
for (var i = 0; i < polygon.Count; i++)
{
//If point is in the polygon
if (polygon[i] == testPoint)
return true;
//Form a segment between the i'th point
var x1 = polygon[i].X;
var y1 = polygon[i].Y;
//And the i+1'th, or if i is the last, with the first point
var i2 = (i+1)%polygon.Count;
var x2 = polygon[i2].X;
var y2 = polygon[i2].Y;
var x = testPoint.X;
var y = testPoint.Y;
//Compute the cross product
var d = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1);
if (d > 0) pos++;
if (d < 0) neg++;
//If the sign changes, then point is outside
if (pos > 0 && neg > 0)
return false;
}
//If no change in direction, then on same side of all segments, and thus inside
return true;
}
-
1Sorry if this seems a bit pedantic, but you should probably just fail (or even assert) if the list's length is less than 3. This is a test for polygons, not a test to see if a point is equal to another point, or that a point is on a line. Handling those cases is a great way to get huge headaches later when something you expect to go one way is going another without telling you that you did something wrong. Also the method name doesn't imply that it covers those cases very well. – Gurgadurgen Jul 23 '16 at 14:02
-
very helpful! if that helps anyone, i've modified & ported that code in another answer: https://stackoverflow.com/a/48941131/516188 maybe someone finds my version clearer. – Emmanuel Touzery Feb 23 '18 at 04:40
-
1very helpful! I just tested this function on a homebrew gamedev of mine : a point & click adventure for the Amiga computer. It simply works straight out of the box, converted into C89, compiled & running on the good old 68000. Thanks! (C version is here : https://github.com/ResistanceVault/rpage/blob/master/rpage/utils.c#L119) – Astrofra Nov 23 '19 at 09:47
The pointPolygonTest function in openCV " determines whether the point is inside a contour, outside, or lies on an edge": http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest

- 8,374
- 6
- 55
- 82
-
OpenCV is a really large library. You really don't want to be using it just for this. – Christopher Barber May 04 '21 at 21:07
fortran's answer almost worked for me except I found I had to translate the polygon so that the point you're testing is the same as the origin. Here is the JavaScript that I wrote to make this work:
function Vec2(x, y) {
return [x, y]
}
Vec2.nsub = function (v1, v2) {
return Vec2(v1[0]-v2[0], v1[1]-v2[1])
}
// aka the "scalar cross product"
Vec2.perpdot = function (v1, v2) {
return v1[0]*v2[1] - v1[1]*v2[0]
}
// Determine if a point is inside a polygon.
//
// point - A Vec2 (2-element Array).
// polyVerts - Array of Vec2's (2-element Arrays). The vertices that make
// up the polygon, in clockwise order around the polygon.
//
function coordsAreInside(point, polyVerts) {
var i, len, v1, v2, edge, x
// First translate the polygon so that `point` is the origin. Then, for each
// edge, get the angle between two vectors: 1) the edge vector and 2) the
// vector of the first vertex of the edge. If all of the angles are the same
// sign (which is negative since they will be counter-clockwise) then the
// point is inside the polygon; otherwise, the point is outside.
for (i = 0, len = polyVerts.length; i < len; i++) {
v1 = Vec2.nsub(polyVerts[i], point)
v2 = Vec2.nsub(polyVerts[i+1 > len-1 ? 0 : i+1], point)
edge = Vec2.nsub(v1, v2)
// Note that we could also do this by using the normal + dot product
x = Vec2.perpdot(edge, v1)
// If the point lies directly on an edge then count it as in the polygon
if (x < 0) { return false }
}
return true
}

- 2,336
- 20
- 17
the way i know is something like that.
you pick a point somewhere outside the polygon it may be far away from the geometry. then you draw a line from this point. i mean you create a line equation with these two points.
then for every line in this polygon, you check if they intersect.
them sum of number of intersected lines give you it is inside or not.
if it is odd : inside
if it is even : outside

- 6,889
- 8
- 33
- 55
-
i just learned : it is Ray casting algorithm where eJames has already talked about – ufukgun Jul 13 '09 at 14:40
-
I find your explanation difficult to follow... what's the other point of the line? – fortran Jul 13 '09 at 15:28
-
Ray casting is generally a bad solution, it doesn't deal well with points that are near a vertex where the cast ray would be close to a side. Winding rule is much more robust and faster, especially for convex shapes – Martin Beckett Jul 13 '09 at 18:30
-
-
"what's the other point of the line?" any point which is garanteed to be outside of the polygon. for example: find minimum x and y for all points. pick x-100, y-100 is a point outside of the polygon. – ufukgun Jul 14 '09 at 06:46
-
@ufukgun, I'm smart enough to read that part, in the text say that's the "from" point, what is the "to"? It doesn't tell. – fortran Jul 14 '09 at 19:33
-
this point is the point that you want to test if it is inside? you have a point A and you want to know that if point A is inside the polygon. then you pick a random point B which is garanteed to be outside the polygon. Then you draw a line from A to B. you intersect with the lines on polygon. then you look the total number of intersection. – ufukgun Jul 15 '09 at 06:51
You have to check that the point to test maintains it's orientation relative to all segments of the convex polygon. If so, it's inside. To do this for each segment check if the determinant of the segment vector say AB and the point's vector say AP preserves it's sign. If the determinant is zero than the point is on the segment.
To expose this in C# code,
public bool IsPointInConvexPolygon(...)
{
Point pointToTest = new Point(...);
Point pointA = new Point(...);
//....
var polygon = new List<Point> { pointA, pointB, pointC, pointD ... };
double prevPosition = 0;
// assuming polygon is convex.
for (var i = 0; i < polygon.Count; i++)
{
var startPointSegment = polygon[i];
// end point is first point if the start point is the last point in the list
// (closing the polygon)
var endPointSegment = polygon[i < polygon.Count - 1 ? i + 1 : 0];
if (pointToTest.HasEqualCoordValues(startPointSegment) ||
pointToTest.HasEqualCoordValues(endPointSegment))
return true;
var position = GetPositionRelativeToSegment(pointToTest, startPointSegment, endPointSegment);
if (position == 0) // point position is zero so we are on the segment, we're on the polygon.
return true;
// after we checked the test point's position relative to the first segment, the position of the point
// relative to all other segments must be the same as the first position. If not it means the point
// is not inside the convex polygon.
if (i > 0 && prevPosition != position)
return false;
prevPosition = position;
}
return true;
}
The determinant calculus,
public double GetPositionRelativeToSegment(Point pointToTest, Point segmentStart, Point segmentEnd)
{
return Math.Sign((pointToTest.X - segmentStart.X) * (segmentEnd.Y - segmentStart.Y) -
(pointToTest.Y - segmentStart.Y) * (segmentEnd.X - segmentStart.X));
}

- 306
- 1
- 11

- 3,400
- 2
- 32
- 23
Or from the man that wrote the book see - geometry page
Specifically this page, he discusses why winding rule is generally better than ray crossing.
edit - Sorry this isn't Jospeh O'Rourke who wrote the excellent book Computational Geometry in C, it's Paul Bourke but still a very very good source of geometry algorithms.

- 94,801
- 28
- 188
- 263
Here is the version I use in my project. It's very elegant and concise. Works for every kind of polygons.
http://www.eecs.umich.edu/courses/eecs380/HANDOUTS/PROJ2/InsidePoly.html
The following code is by Randolph Franklin, it returns 1 for interior points and 0 for exterior points.
int pnpoly(int npol, float *xp, float *yp, float x, float y)
{
int i, j, c = 0;
for (i = 0, j = npol-1; i < npol; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
c = !c;
}
return c;
}

- 21
- 1
- 4