Unit 1: 2D graphics algorithm implementation
Computer Graphics Laboratory notes · PTU syllabus (PGCA1923)
On this page
- Unit summary
- Setting up graphics.h
- Pixels, simple shapes and text formatting
- DDA line algorithm
- Bresenham's line algorithm and comparison with DDA
- Moving wheel using midpoint circle and DDA
- Ellipse using the midpoint algorithm
- 2D transformations on user input
- Boundary fill algorithm
- Scan-line polygon fill algorithm
- Line clipping: Cohen–Sutherland
- Sutherland–Hodgman polygon clipping
- Key terms
- Quick revision
- Important questions
Unit summary
This lab implements 2D graphics: plotting pixels, drawing lines and circles, formatted text, DDA and Bresenham line algorithms, a moving wheel using midpoint circle and DDA, midpoint ellipses, translation, rotation and scaling from user input, triangle rotation, combined scaling and translation, boundary fill, scan-line polygon fill, line clipping and Sutherland–Hodgman polygon clipping.
After this unit you can
- Use graphics library functions to draw primitives and text
- Implement line, circle and ellipse algorithms and simple animation
- Apply 2D transformations to shapes
- Implement filling and clipping algorithms
PTU syllabus topics
- Pixel plotting
- simple 2D shape drawing (lines, circles)
- text formatting with graphics functions
- DDA line-drawing algorithm
- Bresenham's line algorithm comparison
- moving wheel via midpoint circle and DDA algorithms
- ellipse generation via midpoint algorithm
- 2D transformations (translation, rotation, scaling) on user input
- triangle rotation
- combined scaling and translation operations
- boundary fill algorithm
- scan-line polygon fill algorithm
- line clipping algorithms
- Sutherland-Hodgeman polygon clipping
- 1
Start at (0, r)
- 2
Decision p = 1 − r
- 3
If p < 0
Next (x + 1, y); p += 2x + 3
- 4
Else
Next (x + 1, y − 1); p += 2(x − y) + 5
- 5
Plot all 8 symmetric points
- 6
Repeat while x < y
Topic 1
Setting up graphics.h
- graphics.h is the Borland BGI library used in Turbo C++. On modern systems use WinBGIm with Code::Blocks or Dev-C++ (link libbgi, libgdi32, libcomdlg32, libuuid, libole32, liboleaut32), or a DOS emulator running Turbo C++. Every program starts with initgraph and ends with closegraph.
cpp#include <graphics.h>
#include <conio.h>
int main() {
int gd = DETECT, gm;
initgraph(&gd, &gm, (char*)""); // "C:\\TURBOC3\\BGI" in Turbo C++
// drawing code
getch();
closegraph();
return 0;
}Topic 2
Pixels, simple shapes and text formatting
- putpixel(x, y, color)
- Plot one pixel
- line(x1, y1, x2, y2)
- Draw a line
- rectangle(left, top, right, bottom)
- Draw a rectangle
- circle(x, y, r)
- Draw a circle
- arc(x, y, start, end, r)
- Draw an arc between angles
- ellipse(x, y, start, end, xr, yr)
- Draw an ellipse or elliptical arc
- setcolor(c), setfillstyle(pattern, c)
- Set drawing and fill colours
- floodfill(x, y, border)
- Fill an area bounded by the border colour
- outtextxy(x, y, text)
- Write text
- cleardevice(), delay(ms)
- Clear screen; pause
cppsetcolor(YELLOW);
circle(150, 150, 60);
setfillstyle(SOLID_FILL, BLUE);
floodfill(150, 150, YELLOW); // fill inside the yellow circle
setcolor(WHITE);
rectangle(250, 100, 400, 200);
arc(500, 150, 0, 180, 50);
ellipse(320, 320, 0, 360, 100, 50);
putpixel(320, 320, RED);
outtextxy(260, 400, (char*)"Basic shapes");cppsettextstyle(TRIPLEX_FONT, HORIZ_DIR, 3); // font, direction, size
setcolor(LIGHTCYAN);
outtextxy(100, 40, (char*)"Computer Graphics Lab");
settextjustify(CENTER_TEXT, CENTER_TEXT);
settextstyle(SANS_SERIF_FONT, VERT_DIR, 2);
outtextxy(50, 240, (char*)"SBS");Topic 3
DDA line algorithm
cpp#include <cmath>
void ddaLine(int x1, int y1, int x2, int y2) {
int dx = x2 - x1, dy = y2 - y1;
int steps = abs(dx) > abs(dy) ? abs(dx) : abs(dy);
float xinc = dx / (float)steps, yinc = dy / (float)steps;
float x = x1, y = y1;
for (int i = 0; i <= steps; i++) {
putpixel((int)round(x), (int)round(y), GREEN);
x += xinc; y += yinc;
}
}Topic 4
Bresenham's line algorithm and comparison with DDA
cppvoid bresLine(int x1, int y1, int x2, int y2) {
int dx = abs(x2 - x1), dy = abs(y2 - y1);
int sx = x1 < x2 ? 1 : -1, sy = y1 < y2 ? 1 : -1;
int err = dx - dy;
while (true) {
putpixel(x1, y1, CYAN);
if (x1 == x2 && y1 == y2) break;
int e2 = 2 * err;
if (e2 > -dy) { err -= dy; x1 += sx; }
if (e2 < dx) { err += dx; y1 += sy; }
}
}Arithmetic
Floating-point additions and rounding
Integer additions and subtractions only
Speed
Slower
Faster
Accuracy
Rounding errors accumulate on long lines
Exact choice of nearest pixel
Hardware
Needs floating-point support
Suits simple hardware
Topic 5
Moving wheel using midpoint circle and DDA
cpp#include <graphics.h>
#include <cmath>
void midCircle(int xc, int yc, int r, int c) {
int x = 0, y = r, p = 1 - r;
while (x <= y) {
int pts[8][2] = {{x,y},{y,x},{-x,y},{-y,x},{x,-y},{y,-x},{-x,-y},{-y,-x}};
for (auto &q : pts) putpixel(xc + q[0], yc + q[1], c);
x++;
if (p < 0) p += 2 * x + 1; else { y--; p += 2 * (x - y) + 1; }
}
}
void ddaLine(int x1, int y1, int x2, int y2, int c) {
int steps = std::max(abs(x2 - x1), abs(y2 - y1));
float x = x1, y = y1, dx = (x2 - x1) / (float)steps, dy = (y2 - y1) / (float)steps;
for (int i = 0; i <= steps; i++) { putpixel(round(x), round(y), c); x += dx; y += dy; }
}
int main() {
int gd = DETECT, gm; initgraph(&gd, &gm, (char*)"");
int r = 40, y = 300;
for (int xc = 50; xc < 600; xc += 4) {
double a = (xc - 50) / (double)r; // angle rolled = distance / radius
cleardevice();
line(0, y + r, getmaxx(), y + r); // ground
midCircle(xc, y, r, WHITE);
for (int k = 0; k < 4; k++) { // four spokes
double t = a + k * M_PI / 4;
ddaLine(xc - r * cos(t), y - r * sin(t), xc + r * cos(t), y + r * sin(t), YELLOW);
}
delay(30);
}
closegraph();
}Topic 6
Ellipse using the midpoint algorithm
cppvoid plot4(int xc, int yc, int x, int y, int c) {
putpixel(xc + x, yc + y, c); putpixel(xc - x, yc + y, c);
putpixel(xc + x, yc - y, c); putpixel(xc - x, yc - y, c);
}
void midEllipse(int xc, int yc, long rx, long ry) {
long x = 0, y = ry;
double p1 = ry * ry - rx * rx * ry + 0.25 * rx * rx;
while (2 * ry * ry * x < 2 * rx * rx * y) { // region 1
plot4(xc, yc, x, y, LIGHTGREEN);
x++;
if (p1 < 0) p1 += 2 * ry * ry * x + ry * ry;
else { y--; p1 += 2 * ry * ry * x - 2 * rx * rx * y + ry * ry; }
}
double p2 = ry * ry * (x + 0.5) * (x + 0.5) + rx * rx * (y - 1) * (y - 1) - rx * rx * ry * ry;
while (y >= 0) { // region 2
plot4(xc, yc, x, y, LIGHTGREEN);
y--;
if (p2 > 0) p2 += rx * rx - 2 * rx * rx * y;
else { x++; p2 += 2 * ry * ry * x - 2 * rx * rx * y + rx * rx; }
}
}Topic 7
2D transformations on user input
cpp#include <graphics.h>
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int gd = DETECT, gm; initgraph(&gd, &gm, (char*)"");
int x[3] = {200, 300, 250}, y[3] = {200, 200, 120}; // triangle
auto draw = [&](int c) { setcolor(c);
for (int i = 0; i < 3; i++) line(x[i], y[i], x[(i + 1) % 3], y[(i + 1) % 3]); };
draw(WHITE);
int ch; cout << "1 Translate 2 Rotate 3 Scale: "; cin >> ch;
if (ch == 1) { int tx, ty; cin >> tx >> ty; for (int i = 0; i < 3; i++) { x[i] += tx; y[i] += ty; } }
else if (ch == 2) { // rotate about the first vertex
double deg; cin >> deg; double t = deg * M_PI / 180;
int xr = x[0], yr = y[0];
for (int i = 0; i < 3; i++) {
int dx = x[i] - xr, dy = y[i] - yr;
x[i] = xr + round(dx * cos(t) - dy * sin(t));
y[i] = yr + round(dx * sin(t) + dy * cos(t));
}
} else { // scale about the first vertex
double sx, sy; cin >> sx >> sy;
for (int i = 0; i < 3; i++) { x[i] = x[0] + round((x[i] - x[0]) * sx); y[i] = y[0] + round((y[i] - y[0]) * sy); }
}
draw(YELLOW);
getch(); closegraph();
}- Combined scaling and translation: apply scaling about the origin and then translation (or multiply the 3 × 3 matrices T × S and apply the product to each vertex); compare the result with the reverse order to show that order matters.
Topic 8
Boundary fill algorithm
cppvoid boundaryFill4(int x, int y, int fill, int boundary) {
int c = getpixel(x, y);
if (c != boundary && c != fill) {
putpixel(x, y, fill);
boundaryFill4(x + 1, y, fill, boundary); boundaryFill4(x - 1, y, fill, boundary);
boundaryFill4(x, y + 1, fill, boundary); boundaryFill4(x, y - 1, fill, boundary);
}
}
/* usage: setcolor(RED); rectangle(100,100,180,160); boundaryFill4(140,130,GREEN,RED); */Topic 9
Scan-line polygon fill algorithm
cpp#include <algorithm>
#include <vector>
void scanFill(int n, int px[], int py[], int color) {
int ymin = *std::min_element(py, py + n), ymax = *std::max_element(py, py + n);
for (int y = ymin; y <= ymax; y++) {
std::vector<int> xs;
for (int i = 0; i < n; i++) {
int x1 = px[i], y1 = py[i], x2 = px[(i + 1) % n], y2 = py[(i + 1) % n];
if (y1 == y2) continue; // skip horizontal edges
if ((y >= std::min(y1, y2)) && (y < std::max(y1, y2))) // half-open rule avoids double vertices
xs.push_back(x1 + (y - y1) * (x2 - x1) / (y2 - y1));
}
std::sort(xs.begin(), xs.end());
setcolor(color);
for (size_t k = 0; k + 1 < xs.size(); k += 2) line(xs[k], y, xs[k + 1], y); // fill between pairs
}
}Topic 10
Line clipping: Cohen–Sutherland
cpp// Cohen–Sutherland line clipping
const int INSIDE = 0, LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8;
int xmin = 150, ymin = 150, xmax = 450, ymax = 350; // clipping window
int code(int x, int y) {
int c = INSIDE;
if (x < xmin) c |= LEFT; else if (x > xmax) c |= RIGHT;
if (y < ymin) c |= BOTTOM; else if (y > ymax) c |= TOP;
return c;
}
void cohenSutherland(int x1, int y1, int x2, int y2) {
int c1 = code(x1, y1), c2 = code(x2, y2);
bool accept = false;
while (true) {
if (!(c1 | c2)) { accept = true; break; } // both inside
if (c1 & c2) break; // both outside same side
int out = c1 ? c1 : c2; double x, y;
if (out & TOP) { x = x1 + (x2 - x1) * (ymax - y1) / (double)(y2 - y1); y = ymax; }
else if (out & BOTTOM) { x = x1 + (x2 - x1) * (ymin - y1) / (double)(y2 - y1); y = ymin; }
else if (out & RIGHT) { y = y1 + (y2 - y1) * (xmax - x1) / (double)(x2 - x1); x = xmax; }
else { y = y1 + (y2 - y1) * (xmin - x1) / (double)(x2 - x1); x = xmin; }
if (out == c1) { x1 = (int)x; y1 = (int)y; c1 = code(x1, y1); }
else { x2 = (int)x; y2 = (int)y; c2 = code(x2, y2); }
}
rectangle(xmin, ymin, xmax, ymax);
if (accept) { setcolor(YELLOW); line(x1, y1, x2, y2); }
}- Windowing: map a world-coordinate window to a screen viewport with xv = xvmin + (xw − xwmin) × sx and yv = yvmin + (yw − ywmin) × sy; draw the original and the mapped figure side by side to check the result.
Topic 11
Sutherland–Hodgman polygon clipping
cpp#include <vector>
struct P { double x, y; };
// clip polygon against one edge: inside(p) tests the side, cut(a, b) returns the intersection
template <class In, class Cut>
std::vector<P> clipEdge(const std::vector<P>& poly, In inside, Cut cut) {
std::vector<P> out;
for (size_t i = 0; i < poly.size(); i++) {
P s = poly[i], p = poly[(i + 1) % poly.size()];
bool sIn = inside(s), pIn = inside(p);
if (sIn && pIn) out.push_back(p); // in → in: output P
else if (sIn && !pIn) out.push_back(cut(s, p)); // in → out: output I
else if (!sIn && pIn) { out.push_back(cut(s, p)); out.push_back(p); } // out → in: I and P
} // out → out: nothing
return out;
}
std::vector<P> clip(std::vector<P> poly, double xmin, double ymin, double xmax, double ymax) {
auto atX = [](P a, P b, double x) { return P{x, a.y + (b.y - a.y) * (x - a.x) / (b.x - a.x)}; };
auto atY = [](P a, P b, double y) { return P{a.x + (b.x - a.x) * (y - a.y) / (b.y - a.y), y}; };
poly = clipEdge(poly, [&](P p){ return p.x >= xmin; }, [&](P a, P b){ return atX(a, b, xmin); });
poly = clipEdge(poly, [&](P p){ return p.x <= xmax; }, [&](P a, P b){ return atX(a, b, xmax); });
poly = clipEdge(poly, [&](P p){ return p.y >= ymin; }, [&](P a, P b){ return atY(a, b, ymin); });
poly = clipEdge(poly, [&](P p){ return p.y <= ymax; }, [&](P a, P b){ return atY(a, b, ymax); });
return poly;
}- Draw the window, the original polygon in one colour and the clipped polygon in another to check the output.
Key terms
- putpixel
- Function lighting a single pixel
- Midpoint circle algorithm
- Integer circle algorithm using a decision parameter
- Composite transformation
- Combined matrix of several transformations
- Scan-line fill
- Filling between edge intersections on each scan line
- Sutherland–Hodgman
- Polygon clipping against one window edge at a time
Quick revision
- initgraph, putpixel, line, circle, settextstyle, outtextxy.
- DDA vs Bresenham; moving wheel with midpoint circle and DDA spokes.
- Midpoint ellipse; translation, rotation, scaling on input; rotation about a vertex; T × S vs S × T.
- Boundary fill; scan-line fill with sorted intersections.
- Cohen–Sutherland line clipping; Sutherland–Hodgman polygon clipping.
Important exam questions
Practice questions written to the PTU exam pattern for this unit's syllabus: short answers (Section A style) and long answers (Sections B and C style).
Short-answer questions
- Q1.Which function changes the font in graphics.h?
- Q2.Why is Bresenham's algorithm faster than DDA?
- Q3.How is a wheel made to appear to roll?
- Q4.How do you rotate a triangle about one of its vertices?
- Q5.Why are intersections sorted in scan-line fill?
- Q6.What are the four cases in Sutherland–Hodgman clipping?
Long-answer questions
- Q1.Write programs to draw lines using DDA and Bresenham and compare them.
- Q2.Write a program to animate a moving wheel.
- Q3.Write a program to translate, rotate and scale a triangle.
- Q4.Write programs for scan-line fill and Sutherland–Hodgman clipping.
Stuck on this unit?
Message SBS on WhatsApp for help with Computer Graphics Laboratory, or to ask about studying M.Sc IT at Synetic.
