Open In App

CSES Solutions – Point in Polygon

Last Updated : 16 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

You are given a polygon of N vertices and a list of M points. Your task is to determine for each point if it is inside, outside or on the boundary of the polygon.

The polygon consists of n vertices (x1,y1),(x2,y2),…,(xn,yn). The vertices (xi,yi) and (xi+1,yi+1) are adjacent for i=1,2,…,n-1, and the vertices (x1,y1) and (xn,yn) are also adjacent.

Examples:

Input: N = 4, M = 3, vertices = {{1, 1}, {4, 2}, {3, 5}, {1, 4}}, points = {{2, 3}, {3, 1}, {1, 3}}
Output:
INSIDE
OUTSIDE
BOUNDARY

Input: N = 4, M = 3, vertices = {{1, 3}, {1, 2}, {2, 5}, {2, 4}}, points = {{3, 3}, {1, 1}, {1, 3}}
Output:
OUTSIDE
OUTSIDE
BOUNDARY

Approach: To solve the problem, follow the below idea:

The idea is to use cross product is used to determine the orientation of three points. If the cross product is positive, the points are in counterclockwise order. If it’s negative, they are in clockwise order. If it’s zero, the points are collinear. We’ll Sort Points by their X-coordinates to simplify the comparison process.

  • Checks if a point lies on the boundary of a line segment. It does this by comparing the X-coordinates of the points and ensuring that the middle point is equal to the given point.
  • Check if a point is inside or outside a polygon. Calculates the cross products of vectors formed by the polygon vertices and the point. Based on these cross products, checks for intersections and determines if the point lies on the boundary.
  • Prints “INSIDE” if the point is inside the polygon, “OUTSIDE” if it’s outside, and “BOUNDARY” if it lies on the boundary.

Step-by-step algorithm:

  • Create cross product function.
  • Create comparison function based on X-coordinates.
  • Implement function to check if a point is on the boundary.
  • Implement function to check point position relative to polygon.
  • Input polygon vertices and points.
  • Iterate through each point and determine position.
  • Output position for each point.

Below is the implementation of the algorithm:

C++
#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define endl '\n'

// Define complex number type with long long components
#define P complex<ll>

// Get real part of complex number
#define X real()

// Get imaginary part of complex number
#define Y imag()

// Define infinity constant
const ll INF = 1e9 + 7;

// Function to calculate the cross product of three points
ll cross(P a, P b, P c) {
    // Vector from a to b
    P u = b - a;
    // Vector from a to c
    P v = c - a;
    // Cross product of u and v
    ll cp = (conj(u)*v).Y;
    // Return sign of cross product
    return (cp > 0) - (cp < 0);
}

// Function to compare two points by their X-coordinates
bool comp(const P &a, const P &b) {
    // Compare points based on X-coordinate
    return (a.X == b.X) ? (a.Y < b.Y) : (a.X < b.X);
}

// Function to check if a point is on the boundary of the polygon
bool mid(P a, P b, P c) {
    // Create vector of points
    vector<P> v = {a, b, c};
    // Sort points based on X-coordinate
    sort(v.begin(), v.end(), comp);
    // Check if the middle point is equal to c
    return (v[1] == c);
}

// Function to check if a point is inside or outside the polygon
bool check(P a, P b, P c, P d) {
    // Calculate cross product of vectors a-b and a-c
    ll cp1 = cross(a, b, c);
    // Calculate cross product of vectors a-b and a-d
    ll cp2 = cross(a, b, d);
    // Calculate cross product of vectors c-d and c-a
    ll cp3 = cross(c, d, a);
    // Calculate cross product of vectors c-d and c-b
    ll cp4 = cross(c, d, b);
    // Check if points c and d are on different sides of line a-b
    if (cp1 * cp2 < 0 && cp3 * cp4 < 0) return 1;
    // Check if point a lies on line c-d and b lies on opposite side of c-d
    if (cp3 == 0 && mid(c, d, a) && cp4 < 0) return 1;
    // Check if point b lies on line c-d and a lies on opposite side of c-d
    if (cp4 == 0 && mid(c, d, b) && cp3 < 0) return 1;
    // Otherwise, return false
    return 0;
}

int main(){

    // Provided input
    ll n = 4, m = 3;
    vector<pair<ll, ll>> vertices = {{1, 1}, {4, 2}, {3, 5}, {1, 4}};
    vector<pair<ll, ll>> points = {{2, 3}, {3, 1}, {1, 3}};

    // Vector to store the vertices of the polygon
    vector<P> polygon;

    // Input the vertices of the polygon
    for (ll i = 0; i < n; i++) {
        // Add vertex to the polygon vector
        polygon.push_back({vertices[i].first, vertices[i].second});
    }

    // Add the first vertex to the end of the vector to make it a closed polygon
    polygon.push_back(polygon[0]);

    // Loop through the points and check if each point is inside, outside or on the boundary of the polygon
    for (ll i = 0; i < m; i++) {
        // Create complex number representing the point
        P point = {points[i].first, points[i].second};
        // Create complex number representing infinity
        P infinity = {INF, INF};
        // Counter for number of intersections
        ll cnt = 0;
        // Flag to indicate if point lies on boundary
        ll flag = 0;
        for (ll j = 0; j < n; j++) {
            // Calculate cross product of vectors
            ll cp = cross(polygon[j], polygon[j+1], point);
            // If point lies on line segment
            if (cp == 0 && mid(polygon[j], polygon[j+1], point)) {
                // Set flag to indicate boundary
                flag = 1;
                // Exit loop
                break;
            }
            // Check for intersection
            cnt += check(polygon[j], polygon[j+1], point, infinity);
        }
        // If point lies on boundary, output "BOUNDARY"
        if (flag) cout << "BOUNDARY" << endl;
        // If odd number of intersections, point is inside, otherwise outside
        else cout << (cnt & 1 ? "INSIDE" : "OUTSIDE") << endl;
    }

    // Return 0 to indicate successful completion
    return 0;
}
Java
import java.util.*;

class Point implements Comparable<Point> {
    long x, y;

    Point(long x, long y) {
        this.x = x;
        this.y = y;
    }

    public int compareTo(Point p) {
        return Long.compare(this.x, p.x);
    }
}

public class Main {
    static final long INF = (long)1e9 + 7;

    static long cross(Point a, Point b, Point c) {
        Point u = new Point(b.x - a.x, b.y - a.y);
        Point v = new Point(c.x - a.x, c.y - a.y);
        long cp = u.x * v.y - u.y * v.x;
        return Long.signum(cp);
    }

    static boolean mid(Point a, Point b, Point c) {
        // Check if point c lies on the line segment formed by a and b
        if (c.x >= Math.min(a.x, b.x) && c.x <= Math.max(a.x, b.x) &&
            c.y >= Math.min(a.y, b.y) && c.y <= Math.max(a.y, b.y)) {
            // Calculate the cross product of vectors ac and ab
            long cp = cross(a, b, c);
            // If the cross product is zero, points a, b, and c are collinear
            if (cp == 0) {
                return true;
            }
        }
        return false;
    }

    static boolean check(Point a, Point b, Point c, Point d) {
        long cp1 = cross(a, b, c);
        long cp2 = cross(a, b, d);
        long cp3 = cross(c, d, a);
        long cp4 = cross(c, d, b);
        if (cp1 * cp2 < 0 && cp3 * cp4 < 0) return true;
        if (cp3 == 0 && mid(c, d, a) && cp4 < 0) return true;
        if (cp4 == 0 && mid(c, d, b) && cp3 < 0) return true;
        return false;
    }

    public static void main(String[] args) {
        long n = 4, m = 3;
        Point[] vertices = {new Point(1, 1), new Point(4, 2), new Point(3, 5), new Point(1, 4)};
        Point[] points = {new Point(2, 3), new Point(3, 1), new Point(1, 3)};

        List<Point> polygon = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            polygon.add(vertices[i]);
        }
        polygon.add(polygon.get(0));

        for (int i = 0; i < m; i++) {
            Point point = points[i];
            Point infinity = new Point(INF, INF);
            long cnt = 0;
            long flag = 0;
            for (int j = 0; j < n; j++) {
                long cp = cross(polygon.get(j), polygon.get(j+1), point);
                if (cp == 0 && mid(polygon.get(j), polygon.get(j+1), point)) {
                    flag = 1;
                    break;
                }
                cnt += check(polygon.get(j), polygon.get(j+1), point, infinity) ? 1 : 0;
            }
            if (flag == 1) System.out.println("BOUNDARY");
            else System.out.println((cnt % 2 == 1) ? "INSIDE" : "OUTSIDE");
        }
    }
}
Python3
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def cross(a, b, c):
    u = Point(b.x - a.x, b.y - a.y)
    v = Point(c.x - a.x, c.y - a.y)
    cp = u.x * v.y - u.y * v.x
    return cp

def mid(a, b, c):
    if (c.x >= min(a.x, b.x) and c.x <= max(a.x, b.x) and
        c.y >= min(a.y, b.y) and c.y <= max(a.y, b.y)):
        cp = cross(a, b, c)
        if cp == 0:
            return True
    return False

def check(a, b, c, d):
    cp1 = cross(a, b, c)
    cp2 = cross(a, b, d)
    cp3 = cross(c, d, a)
    cp4 = cross(c, d, b)
    if cp1 * cp2 < 0 and cp3 * cp4 < 0:
        return True
    if cp3 == 0 and mid(c, d, a) and cp4 < 0:
        return True
    if cp4 == 0 and mid(c, d, b) and cp3 < 0:
        return True
    return False

n = 4
m = 3
vertices = [Point(1, 1), Point(4, 2), Point(3, 5), Point(1, 4)]
points = [Point(2, 3), Point(3, 1), Point(1, 3)]

polygon = vertices + [vertices[0]]

INF = 10 ** 9 + 7

for point in points:
    cnt = 0
    flag = 0
    infinity = Point(INF, INF)
    for j in range(n):
        cp = cross(polygon[j], polygon[j + 1], point)
        if cp == 0 and mid(polygon[j], polygon[j + 1], point):
            flag = 1
            break
        cnt += 1 if check(polygon[j], polygon[j + 1], point, infinity) else 0
    if flag == 1:
        print("BOUNDARY")
    else:
        print("INSIDE" if cnt % 2 == 1 else "OUTSIDE")
JavaScript
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

function cross(a, b, c) {
    let u = new Point(b.x - a.x, b.y - a.y);
    let v = new Point(c.x - a.x, c.y - a.y);
    let cp = u.x * v.y - u.y * v.x;
    return cp;
}

function mid(a, b, c) {
    if (c.x >= Math.min(a.x, b.x) && c.x <= Math.max(a.x, b.x) &&
        c.y >= Math.min(a.y, b.y) && c.y <= Math.max(a.y, b.y)) {
        let cp = cross(a, b, c);
        if (cp === 0) {
            return true;
        }
    }
    return false;
}

function check(a, b, c, d) {
    let cp1 = cross(a, b, c);
    let cp2 = cross(a, b, d);
    let cp3 = cross(c, d, a);
    let cp4 = cross(c, d, b);
    if (cp1 * cp2 < 0 && cp3 * cp4 < 0) {
        return true;
    }
    if (cp3 === 0 && mid(c, d, a) && cp4 < 0) {
        return true;
    }
    if (cp4 === 0 && mid(c, d, b) && cp3 < 0) {
        return true;
    }
    return false;
}

let n = 4;
let m = 3;
let vertices = [new Point(1, 1), new Point(4, 2), new Point(3, 5), new Point(1, 4)];
let points = [new Point(2, 3), new Point(3, 1), new Point(1, 3)];

let polygon = vertices.concat([vertices[0]]);

const INF = 10 ** 9 + 7;

for (let point of points) {
    let cnt = 0;
    let flag = 0;
    let infinity = new Point(INF, INF);
    for (let j = 0; j < n; j++) {
        let cp = cross(polygon[j], polygon[j + 1], point);
        if (cp === 0 && mid(polygon[j], polygon[j + 1], point)) {
            flag = 1;
            break;
        }
        cnt += check(polygon[j], polygon[j + 1], point, infinity) ? 1 : 0;
    }
    if (flag === 1) {
        console.log("BOUNDARY");
    } else {
        console.log(cnt % 2 === 1 ? "INSIDE" : "OUTSIDE");
    }
}

Output
INSIDE
OUTSIDE
BOUNDARY

Time Complexity: O(nmlog(n)), n is the number of vertices in the polygon, m is the number of points to be checked
Auxiliary Space: O(m), as it needs to store the m points in memory.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads