Count Integral points inside a Triangle

Last Updated : 18 Sep, 2026

Given three non-collinear points p, q, and r with integer coordinates in the X-Y plane, find the number of integral (lattice) points that lie strictly inside the triangle formed by these three points. 

  • A point is called an integral/lattice point if both its x-coordinate and y-coordinate are integers. 
  • Points lying on the boundary of the triangle are not counted.

Examples: 

Input: p[] = [0, 0], q[] = [0,5], r[] = [5,0]
Output: 6
Explanation:

blobid1_1718772838

As shown in figure, points (1,1) (1,2) (1,3) (2,1) (2,2) and (3,1) are the integral points inside the triangle. So total 6 are there.

Input: p[] = [62,-3], q[] = [5,-45], r[] = [-19,-23]
Output: 1129
Explanation: There are 1129 integral points in the triangle formed by p, q and r.

Try It Yourself
redirect icon

[Naive Approach] Checking Points in Bounding Rectangle - O(W Ă— H) Time and O(1) Space

The idea is to check every integral point inside the bounding rectangle of the triangle and find if it lies strictly inside the triangle using cross products.

Working of Approach:

  • Find the minimum and maximum x and y coordinates among the three vertices.
  • Traverse all integral points (x, y) inside this bounding rectangle.
  • For each point, calculate its cross product with all three edges of the triangle.
  • If all cross products have the same sign and none is zero, the point lies strictly inside the triangle.
  • Count all such points and return the total.
C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;

// Calculate cross product of AB and AP.
long long cross(vector<int> &a, vector<int> &b, long long x, long long y)
{
    return 1LL * (b[0] - a[0]) * (y - a[1]) - 1LL * (b[1] - a[1]) * (x - a[0]);
}

// Check if the point lies strictly inside the triangle.
bool isInside(vector<int> &p, vector<int> &q, vector<int> &r, long long x, long long y)
{

    long long c1 = cross(p, q, x, y);
    long long c2 = cross(q, r, x, y);
    long long c3 = cross(r, p, x, y);

    // Points on the boundary are not counted.
    if (c1 == 0 || c2 == 0 || c3 == 0)
        return false;

    // All cross products must have the same sign.
    return (c1 > 0 && c2 > 0 && c3 > 0) || (c1 < 0 && c2 < 0 && c3 < 0);
}

int internalCount(vector<int> &p, vector<int> &q, vector<int> &r)
{

    int minX = min({p[0], q[0], r[0]});
    int maxX = max({p[0], q[0], r[0]});
    int minY = min({p[1], q[1], r[1]});
    int maxY = max({p[1], q[1], r[1]});

    int res = 0;

    // Check every integral point in the bounding rectangle.
    for (long long x = minX; x <= maxX; x++)
    {
        for (long long y = minY; y <= maxY; y++)
        {

            if (isInside(p, q, r, x, y))
                res++;
        }
    }

    return res;
}

int main()
{

    vector<int> p = {0, 0};
    vector<int> q = {0, 5};
    vector<int> r = {5, 0};

    cout << internalCount(p, q, r);

    return 0;
}
Java
import java.util.*;

class GFG {

    // Calculate cross product of AB and AP.
    long cross(int[] a, int[] b, long x, long y)
    {
        return 1L * (b[0] - a[0]) * (y - a[1])
            - 1L * (b[1] - a[1]) * (x - a[0]);
    }

    // Check if the point lies strictly inside the triangle.
    boolean isInside(int[] p, int[] q, int[] r, long x,
                     long y)
    {

        long c1 = cross(p, q, x, y);
        long c2 = cross(q, r, x, y);
        long c3 = cross(r, p, x, y);

        // Points on the boundary are not counted.
        if (c1 == 0 || c2 == 0 || c3 == 0)
            return false;

        // All cross products must have the same sign.
        return (c1 > 0 && c2 > 0 && c3 > 0)
            || (c1 < 0 && c2 < 0 && c3 < 0);
    }

    int internalCount(int[] p, int[] q, int[] r)
    {

        int minX = Math.min(p[0], Math.min(q[0], r[0]));
        int maxX = Math.max(p[0], Math.max(q[0], r[0]));
        int minY = Math.min(p[1], Math.min(q[1], r[1]));
        int maxY = Math.max(p[1], Math.max(q[1], r[1]));

        int res = 0;

        // Check every integral point in the bounding
        // rectangle.
        for (long x = minX; x <= maxX; x++) {
            for (long y = minY; y <= maxY; y++) {

                if (isInside(p, q, r, x, y))
                    res++;
            }
        }

        return res;
    }

    public static void main(String[] args)
    {

        GFG obj = new GFG();

        int[] p = { 0, 0 };
        int[] q = { 0, 5 };
        int[] r = { 5, 0 };

        System.out.println(obj.internalCount(p, q, r));
    }
}
Python
def cross(a, b, x, y):
    # Calculate cross product of AB and AP.
    return (b[0] - a[0]) * (y - a[1]) - (b[1] - a[1]) * (x - a[0])


def isInside(p, q, r, x, y):

    c1 = cross(p, q, x, y)
    c2 = cross(q, r, x, y)
    c3 = cross(r, p, x, y)

    # Points on the boundary are not counted.
    if c1 == 0 or c2 == 0 or c3 == 0:
        return False

    # All cross products must have the same sign.
    return (c1 > 0 and c2 > 0 and c3 > 0) or (c1 < 0 and c2 < 0 and c3 < 0)


def internalCount(p, q, r):

    minX = min(p[0], q[0], r[0])
    maxX = max(p[0], q[0], r[0])
    minY = min(p[1], q[1], r[1])
    maxY = max(p[1], q[1], r[1])

    res = 0

    # Check every integral point in the bounding rectangle.
    for x in range(minX, maxX + 1):
        for y in range(minY, maxY + 1):
            if isInside(p, q, r, x, y):
                res += 1

    return res


if __name__ == "__main__":

    p = [0, 0]
    q = [0, 5]
    r = [5, 0]

    print(internalCount(p, q, r))
C#
using System;

class GFG {

    // Calculate cross product of AB and AP.
    long Cross(int[] a, int[] b, long x, long y)
    {
        return 1L * (b[0] - a[0]) * (y - a[1])
            - 1L * (b[1] - a[1]) * (x - a[0]);
    }

    // Check if the point lies strictly inside the triangle.
    bool IsInside(int[] p, int[] q, int[] r, long x, long y)
    {

        long c1 = Cross(p, q, x, y);
        long c2 = Cross(q, r, x, y);
        long c3 = Cross(r, p, x, y);

        // Points on the boundary are not counted.
        if (c1 == 0 || c2 == 0 || c3 == 0)
            return false;

        // All cross products must have the same sign.
        return (c1 > 0 && c2 > 0 && c3 > 0)
            || (c1 < 0 && c2 < 0 && c3 < 0);
    }

    public int internalCount(int[] p, int[] q, int[] r)
    {

        int minX = Math.Min(p[0], Math.Min(q[0], r[0]));
        int maxX = Math.Max(p[0], Math.Max(q[0], r[0]));
        int minY = Math.Min(p[1], Math.Min(q[1], r[1]));
        int maxY = Math.Max(p[1], Math.Max(q[1], r[1]));

        int res = 0;

        // Check every integral point in the bounding
        // rectangle.
        for (long x = minX; x <= maxX; x++) {
            for (long y = minY; y <= maxY; y++) {

                if (IsInside(p, q, r, x, y))
                    res++;
            }
        }

        return res;
    }

    public static void Main()
    {

        GFG obj = new GFG();

        int[] p = { 0, 0 };
        int[] q = { 0, 5 };
        int[] r = { 5, 0 };

        Console.WriteLine(obj.internalCount(p, q, r));
    }
}
JavaScript
function cross(a, b, x, y)
{
    // Calculate cross product of AB and AP.
    return ((b[0] - a[0]) * (y - a[1])
            - (b[1] - a[1]) * (x - a[0]));
}

function isInside(p, q, r, x, y)
{

    let c1 = cross(p, q, x, y);
    let c2 = cross(q, r, x, y);
    let c3 = cross(r, p, x, y);

    // Points on the boundary are not counted.
    if (c1 === 0 || c2 === 0 || c3 === 0)
        return false;

    // All cross products must have the same sign.
    return (c1 > 0 && c2 > 0 && c3 > 0)
           || (c1 < 0 && c2 < 0 && c3 < 0);
}

function internalCount(p, q, r)
{

    let minX = Math.min(p[0], q[0], r[0]);
    let maxX = Math.max(p[0], q[0], r[0]);
    let minY = Math.min(p[1], q[1], r[1]);
    let maxY = Math.max(p[1], q[1], r[1]);

    let res = 0;

    // Check every integral point in the bounding rectangle.
    for (let x = minX; x <= maxX; x++) {
        for (let y = minY; y <= maxY; y++) {
            if (isInside(p, q, r, x, y))
                res++;
        }
    }

    return res;
}

// Driver Code
let p = [ 0, 0 ];
let q = [ 0, 5 ];
let r = [ 5, 0 ];

console.log(internalCount(p, q, r));

Output
6

[Expected Approach] Using Pick's Theorem - O(log C) Time and O(1) Space

The idea is to use Pick's Theorem, which relates the area of a lattice triangle with its interior and boundary lattice points.

Pick's Theorem, states that the following equation holds true for a simple polygon.

A = I + (B / 2) - 1

  • A ==> Area of Polygon
  • B ==> Number of integral points on edges of polygon
  • I ==> Number of integral points inside the polygon

Using the above formula, we can deduce:

  • I = (2A - B + 2) / 2

We can find A (area of the triangle) using the Shoelace Formula.

  • A = 1/2 * abs(x1(y2 - y3) + x2(y3 - y1) + x3(y1 - y2))

How to Find B (Number of Integral Points on Edges of a Triangle)?

We can find the number of integral points between any two vertices V1 and V2 of the triangle using the following:

  • If the edge joining V1 and V2 is parallel to the X-axis, the number of integral points between the vertices is abs(V1.x - V2.x) - 1.
  • If the edge is parallel to the Y-axis, the number of integral points between the vertices is abs(V1.y - V2.y) - 1.
  • Otherwise, the number of integral points between the vertices can be found using GCD(abs(V1.x - V2.x), abs(V1.y - V2.y)) - 1.

The above GCD formula also works for horizontal and vertical edges, so it can be used directly in the implementation.

We calculate this value for all three edges and add the three vertices to obtain the total number of boundary points.

The formula for finding the integral points between two vertices can be derived using simple geometry. One way to understand it is to shift the edge such that one of its vertices lies at the origin.

Let us understand with an example:
Input: p[] = [0, 0], q[] = [0,5], r[] = [5,0]

  • For edges (p, q), (q, r) and (r, p), the number of integral points between the vertices is 4, 4 and 4, respectively. Adding the 3 vertices gives boundary = 15.
  • Using the Shoelace formula, doubleArea = |0 + 25 + 0| = 25.
  • Applying Pick's theorem, internalCount = (25 - 15 + 2) / 2 = 6.
  • Hence, the number of integral points strictly inside the triangle is 6.
blobid1_1718772838
C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;

int gcd(int a, int b)
{
    while (b != 0)
    {
        int temp = a % b;
        a = b;
        b = temp;
    }

    return a;
}

int getBoundaryCount(vector<int> &p, vector<int> &q)
{
    return gcd(abs(p[0] - q[0]), abs(p[1] - q[1])) - 1;
}

int internalCount(vector<int> &p, vector<int> &q, vector<int> &r)
{

    // Count all lattice points on the boundary.
    int boundary = getBoundaryCount(p, q) + getBoundaryCount(q, r) + getBoundaryCount(r, p) + 3;

    // Calculate twice the area of the triangle.
    int doubleArea = abs(p[0] * (q[1] - r[1]) + q[0] * (r[1] - p[1]) + r[0] * (p[1] - q[1]));

    // Apply Pick's theorem to find interior lattice points.
    return (doubleArea - boundary + 2) / 2;
}

int main()
{

    vector<int> p = {0, 0};
    vector<int> q = {0, 5};
    vector<int> r = {5, 0};

    cout << internalCount(p, q, r);

    return 0;
}
Java
import java.util.*;

class GFG {

    int gcd(int a, int b)
    {
        while (b != 0) {
            int temp = a % b;
            a = b;
            b = temp;
        }

        return a;
    }

    int getBoundaryCount(int[] p, int[] q)
    {
        return gcd(Math.abs(p[0] - q[0]),
                   Math.abs(p[1] - q[1]))
            - 1;
    }

    int internalCount(int[] p, int[] q, int[] r)
    {

        // Count all lattice points on the boundary.
        int boundary = getBoundaryCount(p, q)
                       + getBoundaryCount(q, r)
                       + getBoundaryCount(r, p) + 3;

        // Calculate twice the area of the triangle.
        int doubleArea = Math.abs(p[0] * (q[1] - r[1])
                                  + q[0] * (r[1] - p[1])
                                  + r[0] * (p[1] - q[1]));

        // Apply Pick's theorem to find interior lattice
        // points.
        return (doubleArea - boundary + 2) / 2;
    }

    public static void main(String[] args)
    {

        GFG obj = new GFG();

        int[] p = { 0, 0 };
        int[] q = { 0, 5 };
        int[] r = { 5, 0 };

        System.out.println(obj.internalCount(p, q, r));
    }
}
Python
from math import gcd
from typing import List


def gcd(a: int, b: int) -> int:
    while b!= 0:
        temp = a % b
        a = b
        b = temp
    return a


def getBoundaryCount(p: List[int], q: List[int]) -> int:
    return gcd(abs(p[0] - q[0]), abs(p[1] - q[1])) - 1


def internalCount(p: List[int], q: List[int], r: List[int]) -> int:
    # Count all lattice points on the boundary.
    boundary = getBoundaryCount(p, q) + getBoundaryCount(q, r) + getBoundaryCount(r, p) + 3

    # Calculate twice the area of the triangle.
    doubleArea = abs(p[0] * (q[1] - r[1]) + q[0] * (r[1] - p[1]) + r[0] * (p[1] - q[1]))

    # Apply Pick's theorem to find interior lattice points.
    return (doubleArea - boundary + 2) // 2


if __name__ == "__main__":
    p = [0, 0]
    q = [0, 5]
    r = [5, 0]

    print(internalCount(p, q, r))
C#
using System;

class GFG {

    int Gcd(int a, int b)
    {
        while (b != 0) {
            int temp = a % b;
            a = b;
            b = temp;
        }

        return a;
    }

    int getBoundaryCount(int[] p, int[] q)
    {
        return Gcd(Math.Abs(p[0] - q[0]),
                   Math.Abs(p[1] - q[1]))
            - 1;
    }

    public int internalCount(int[] p, int[] q, int[] r)
    {

        // Count all lattice points on the boundary.
        int boundary = getBoundaryCount(p, q)
                       + getBoundaryCount(q, r)
                       + getBoundaryCount(r, p) + 3;

        // Calculate twice the area of the triangle.
        int doubleArea = Math.Abs(p[0] * (q[1] - r[1])
                                  + q[0] * (r[1] - p[1])
                                  + r[0] * (p[1] - q[1]));

        // Apply Pick's theorem to find interior lattice
        // points.
        return (doubleArea - boundary + 2) / 2;
    }

    public static void Main()
    {

        GFG obj = new GFG();

        int[] p = { 0, 0 };
        int[] q = { 0, 5 };
        int[] r = { 5, 0 };

        Console.WriteLine(obj.internalCount(p, q, r));
    }
}
JavaScript
function gcd(a, b)
{
    while (b != 0) {
        let temp = a % b;
        a = b;
        b = temp;
    }
    return a;
}

function getBoundaryCount(p, q)
{
    return gcd(Math.abs(p[0] - q[0]), Math.abs(p[1] - q[1]))
           - 1;
}

function internalCount(p, q, r)
{
    // Count all lattice points on the boundary.
    let boundary = getBoundaryCount(p, q)
                   + getBoundaryCount(q, r)
                   + getBoundaryCount(r, p) + 3;

    // Calculate twice the area of the triangle.
    let doubleArea = Math.abs(p[0] * (q[1] - r[1])
                              + q[0] * (r[1] - p[1])
                              + r[0] * (p[1] - q[1]));

    // Apply Pick's theorem to find interior lattice points.
    return Math.floor((doubleArea - boundary + 2) / 2);
}

// Driver Code
let p = [ 0, 0 ];
let q = [ 0, 5 ];
let r = [ 5, 0 ];

console.log(internalCount(p, q, r));

Output
6
Comment