C++ Program to Implement Cohen Sutherland Algorithm

The Cohen-Sutherland Line Clipping Algorithm is one of the most widely used algorithms in computer graphics for clipping line segments against a rectangular viewport. It works by assigning a 4-bit region code to each endpoint of a line to quickly determine whether the line is fully inside the window, fully outside, or needs to be clipped. The algorithm avoids expensive intersection calculations whenever possible, making it very efficient for real-time rendering pipelines.

Region Codes

Each endpoint is assigned a 4-character code (stored as a character array) based on its position relative to the clipping window. The window boundaries in this program are: left = 150, right = 450, top = 100, bottom = 350.

  • code[0] = '1' if the point is above the top edge (y < 100)
  • code[1] = '1' if the point is below the bottom edge (y > 350)
  • code[2] = '1' if the point is to the right of the right edge (x > 450)
  • code[3] = '1' if the point is to the left of the left edge (x < 150)
#include<iostream.h>   // Standard input-output stream
#include<conio.h>       // Console input-output (getch)
#include<stdlib.h>      // Standard library utilities
#include<dos.h>         // DOS-specific functions
#include<math.h>        // Math functions (fabs, etc.)
#include<graphics.h>    // Turbo C++ graphics library

// Structure to hold a 2-D point and its region code
typedef struct Coordinate
{
    int x, y;       // Screen coordinates
    char code[4];   // 4-bit region code: [above, below, right, left]
} PT;

// ---- Function prototypes ----
void  drawWindow();
void  drawLine(PT startPt, PT endPt, int colour);
PT    assignRegionCode(PT point);
int   checkVisibility(PT startPt, PT endPt);
PT    clipEndpoint(PT movingPt, PT fixedPt);

// ---- Main ----
main()
{
    int graphicsDriver = DETECT, graphicsMode;
    PT startPt, endPt;

    initgraph(&graphicsDriver, &graphicsMode, "C:\\tc\\bgi");
    cleardevice();

    cout << "\n\tEnter endpoint 1 (x y): ";
    cin  >> startPt.x >> startPt.y;
    cout << "\n\tEnter endpoint 2 (x y): ";
    cin  >> endPt.x >> endPt.y;

    cleardevice();
    drawWindow();               // Draw the clipping rectangle in red
    getch();
    drawLine(startPt, endPt, 15); // Draw original line in white
    getch();

    // Assign region codes to both endpoints
    startPt = assignRegionCode(startPt);
    endPt   = assignRegionCode(endPt);

    int visibilityResult = checkVisibility(startPt, endPt);

    switch (visibilityResult)
    {
        case 0: // Trivially accepted: line fully inside window
            cleardevice();
            drawWindow();
            drawLine(startPt, endPt, 15);
            break;

        case 1: // Trivially rejected: line fully outside window
            cleardevice();
            drawWindow();
            break;

        case 2: // Line partially outside: clip both endpoints and redraw
            cleardevice();
            startPt = clipEndpoint(startPt, endPt);
            endPt   = clipEndpoint(endPt, startPt);
            drawWindow();
            drawLine(startPt, endPt, 15);
            break;
    }

    getch();
    closegraph();
    return 0;
}

// Draws the red clipping rectangle window
void drawWindow()
{
    setcolor(RED);
    line(150, 100, 450, 100); // Top edge
    line(450, 100, 450, 350); // Right edge
    line(450, 350, 150, 350); // Bottom edge
    line(150, 350, 150, 100); // Left edge
}

// Draws a line between two points in the specified colour
void drawLine(PT startPt, PT endPt, int colour)
{
    setcolor(colour);
    line(startPt.x, startPt.y, endPt.x, endPt.y);
}

// Assigns a 4-bit region code to a point based on its position
PT assignRegionCode(PT point)
{
    PT tempPt;
    tempPt.x = point.x;
    tempPt.y = point.y;

    tempPt.code[0] = (point.y < 100) ? '1' : '0'; // Above top
    tempPt.code[1] = (point.y > 350) ? '1' : '0'; // Below bottom
    tempPt.code[2] = (point.x > 450) ? '1' : '0'; // Right of right edge
    tempPt.code[3] = (point.x < 150) ? '1' : '0'; // Left of left edge

    return tempPt;
}

// Returns: 0 = fully inside, 1 = fully outside, 2 = partially inside
int checkVisibility(PT startPt, PT endPt)
{
    int bit;

    // Check if both endpoints are inside (all code bits are '0')
    for (bit = 0; bit < 4; bit++)
    {
        if (startPt.code[bit] != '0' || endPt.code[bit] != '0')
        {
            // At least one bit is set; check if trivially outside
            for (bit = 0; bit < 4; bit++)
            {
                if (startPt.code[bit] == '1' && endPt.code[bit] == '1')
                    return 1; // Both points on same outside side
            }
            return 2; // Partially inside: needs clipping
        }
    }
    return 0; // Fully inside
}

// Clips one endpoint of the line against the window boundary
PT clipEndpoint(PT movingPt, PT fixedPt)
{
    PT clippedPt;
    int clippedX, clippedY;
    float slope;

    // Clip against vertical boundaries (left and right)
    if (movingPt.code[3] == '1')  clippedX = 150; // Left edge
    if (movingPt.code[2] == '1')  clippedX = 450; // Right edge

    if (movingPt.code[3] == '1' || movingPt.code[2] == '1')
    {
        slope = (float)(fixedPt.y - movingPt.y) / (fixedPt.x - movingPt.x);
        clippedY = (int)(movingPt.y + slope * (clippedX - movingPt.x));
        clippedPt.x = clippedX;
        clippedPt.y = clippedY;
        for (int bit = 0; bit < 4; bit++)
            clippedPt.code[bit] = movingPt.code[bit];
        if (clippedPt.y <= 350 && clippedPt.y >= 100)
            return clippedPt;
    }

    // Clip against horizontal boundaries (top and bottom)
    if (movingPt.code[0] == '1')  clippedY = 100; // Top edge
    if (movingPt.code[1] == '1')  clippedY = 350; // Bottom edge

    if (movingPt.code[0] == '1' || movingPt.code[1] == '1')
    {
        slope = (float)(fixedPt.y - movingPt.y) / (fixedPt.x - movingPt.x);
        clippedX = (int)(movingPt.x + (clippedY - movingPt.y) / slope);
        clippedPt.x = clippedX;
        clippedPt.y = clippedY;
        for (int bit = 0; bit < 4; bit++)
            clippedPt.code[bit] = movingPt.code[bit];
        return clippedPt;
    }

    return movingPt; // No clipping needed
}

How the Code Works

  1. User input – The program reads the two endpoints of the line from the user, then draws the clipping window and the original (unclipped) line.
  2. Region code assignment (assignRegionCode) – Each endpoint gets a 4-character code. A bit set to '1' means the point is outside on that side; '0' means it is inside on that side.
  3. Visibility test (checkVisibility) – If all four code bits of both endpoints are '0', the line is trivially accepted (return 0). If any matching bit is '1' in both endpoints (they are on the same outside side), the line is trivially rejected (return 1). Otherwise it is partially inside (return 2).
  4. Clipping (clipEndpoint) – For a partially visible line, each outside endpoint is moved to the intersection with the relevant window edge. The slope formula determines the exact intersection coordinate. Vertical clipping is tested first, and if the resulting y is still out of range, horizontal clipping is applied.
  5. Redraw – After clipping, the window and the clipped line are redrawn. Only the portion of the line that lies inside the rectangle is visible.

Output

Output
Cohen-Sutherland Line Clipping Output

Output Explanation

The screenshot shows three stages: the clipping window (red rectangle), the original line drawn across the screen, and finally the clipped result — only the portion of the line that lies inside the red rectangle is redrawn. This demonstrates all three cases of the algorithm: trivially accepted, trivially rejected, and partially clipped lines depending on where the input endpoints are placed.


See Also


Conclusion

The Cohen-Sutherland Algorithm is an elegant and efficient solution to the line-clipping problem in computer graphics. By using bitwise region codes, it quickly eliminates trivially inside or outside cases and only performs the more costly intersection calculations when necessary. It remains a staple topic in graphics curricula and is the conceptual foundation for more advanced clipping algorithms such as Liang-Barsky and Cyrus-Beck.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.