A consolidated theory guide covering the eight‑way symmetry technique used to generalize midpoint line drawing to any octant, and the two classical line‑clipping algorithms — Cohen‑Sutherland (region‑code based) and Cyrus‑Beck (parametric, vector based) — with their mathematics, worked examples, and diagrams.
Line drawing
A geometric shortcut that lets a line‑drawing routine written for a single octant (Zone 0) be reused for lines pointing in any of the eight directions around the origin, by reflecting/rotating coordinates into Zone 0, drawing there, then mapping the result back.
It grew out of the same "exploit symmetry to avoid recomputation" idea used in Bresenham's circle algorithm, where one computed octant is mirrored eight times.
Line clipping
One of the earliest (1967‑68) and most widely taught line‑clipping algorithms, developed by Danny Cohen and Ivan Sutherland. It encodes the position of a point relative to a rectangular clip window using a 4‑bit outcode, enabling fast trivial accept/reject decisions before doing any expensive intersection math.
Line clipping
A more general, parametric line‑clipping algorithm (Cyrus & Beck, 1978) that represents the line with a parametric equation and uses vector dot products with boundary normals to find the exact parametric range that lies inside the clip region. Because it relies only on edges and normals, it extends naturally to convex polygons and 3‑D polyhedra.
The midpoint line‑drawing algorithm is normally derived only for lines in the first octant (slope between 0 and 1, moving right and up). Instead of re‑deriving the algorithm for every possible direction, the plane around a line's starting point is divided into 8 zones (octants). Any line segment is first classified into a zone, then its endpoints are mathematically transformed into the equivalent line in Zone 0, drawn with the standard midpoint algorithm, and finally the computed pixels are transformed back into the original zone.
Input: 2 endpoints — (x₀, y₀) and (x₁, y₁)
ConvertToZone0 /
OriginalZone for that zone.Given endpoints (x₁,y₁) and (x₂,y₂), compute dx = x₂ − x₁ and
dy = y₂ − y₁. The zone is decided first by which axis dominates
(|dx| > |dy| vs |dy| ≥ |dx|), then by the signs of dx and dy.
| Zone | Condition | Zone | Condition |
|---|---|---|---|
| 0 | dx>0, dy≥0, |dx|>|dy| | 4 | dx<0, dy≤0, |dx|>|dy| |
| 1 | dx>0, dy>0, |dy|>|dx| | 5 | dx<0, dy<0, |dy|>|dx| |
| 2 | dx<0, dy>0, |dy|>|dx| | 6 | dx>0, dy<0, |dy|>|dx| |
| 3 | dx<0, dy>0, |dx|>|dy| | 7 | dx>0, dy<0, |dx|>|dy| |
Each zone has a simple coordinate swap/negation that maps it onto Zone 0 (first octant, |dx| ≥ dy ≥ 0):
| Zone | (X,Y) → Zone 0 |
|---|---|
| 1 | (Y, X) |
| 2 | (Y, −X) |
| 3 | (−X, Y) |
| 4, 5, 6, 7 | Mirror of 3, 2, 1, 0 (left as exercise / DIY in source slides) |
After the midpoint algorithm produces pixels (x, y) in Zone 0, the inverse mapping restores the original zone:
| Zone | (X,Y) → Original Zone |
|---|---|
| 1 | (Y, X) |
| 2 | (−Y, X) |
| 3 | (−X, Y) |
| 4, 5, 6, 7 | Symmetric inverses (DIY in source slides) |
Find the first pixels of the line from (−10,−20) to (−20,70).
Step 1 (zone): dx = −10, dy = 90, |dy| > |dx| and dx<0, dy>0 ⇒ Zone 2.
Step 2 (to Zone 0): using (x=Y, y=−X): start (−10,−20)→(−20,10); end (−20,70)→(70,20).
Step 3 (midpoint on Zone 0): dx′=90, dy′=10, D=2(10)−90=−70, ΔNE=2(10−90)=−160, ΔE=2(10)=20 — the standard decision loop is then run to generate pixels such as (−20,10), (−19,10), (−18,10) …
Step 4 (back to Zone 2, x=−Y′, y=X′): pixels (−20,10)→(−10,−20), (−19,10)→(−10,−19), (−18,10)→(−10,−18), … reproducing the true pixels of the original line.
Clipping removes (or trims) the parts of a picture that fall outside a rectangular clip window so that only the portion inside the visible viewport is drawn — the same idea as a physical picture frame cutting off everything outside its edges. In raster graphics, clipping can be done analytically (before scan conversion, for lines & polygons), during scan conversion (scissoring — used for curves, where only checking extrema suffices), or while writing individual pixels (when only a few pixels of an otherwise‑fitting shape stick out).
World space is divided into 9 regions by extending the window's 4 edges. Each region gets a unique 4‑bit code:
| Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|
| Above | Below | Right | Left |
The window itself always has outcode 0000.
The same idea extends to a 6‑bit outcode for 3‑D clipping against a box, adding near and far planes along z:
| 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|
| Near | Far | Above | Below | Right | Left |
Bits 4–5 are set by comparing z against zmin and zmax the same way x and y are compared in 2‑D.
A line is completely inside the window (and can be drawn as‑is) when both endpoint outcodes are zero:
A line is completely outside the window (and can be discarded entirely) when both endpoints share at least one "outside" bit — i.e. they are both above, both below, both left, or both right of the window:
If neither condition holds, the line is only partially inside/outside and must actually be clipped against one boundary at a time.
OC1 AND OC2 ≠ 0000 → reject the whole segment.Using the line's slope m = (y₂ − y₁) / (x₂ − x₁), the exact
crossing point on each boundary is found analytically:
| Boundary | Fixed coordinate | Solve for the other coordinate |
|---|---|---|
| Left | x = xmin | y = y₁ + m·(xmin − x₁) |
| Right | x = xmax | y = y₁ + m·(xmax − x₁) |
| Bottom | y = ymin | x = x₁ + (1/m)·(ymin − y₁) |
| Top | y = ymax | x = x₁ + (1/m)·(ymax − y₁) |
Clip region (0,0)–(300,200). Line: (50,−125) to (−100,225).
OC1 (50,−125): y < 0 → below ⇒ 0100.
OC2 (−100,225): x < 0 → left, y > 200 → above ⇒ 1001.
OC1 AND OC2 = 0000 (not trivially rejected) and neither is 0000 (not trivially
accepted) → clipping is required. Clipping P1 against the bottom boundary
(slope m = −7/3) moves P1 to (−3.57, 0), whose new outcode is 0001
(left). Now OC1 AND OC2 = 0001 → trivially rejected: both points share the
"left" bit, so the visible line lies entirely to the left of the window and the whole
segment is discarded.
The same iterative logic shown visually for a line whose endpoints start in opposite corner regions, [0101] (left+below) and [1010] (right+above):
Any point on the segment from P₀(x₀,y₀) to P₁(x₁,y₁) can be written as a function of a single parameter t:
At t = 0, P(t) = P₀; at t = 1,
P(t) = P₁. All points with 0 ≤ t ≤ 1 lie strictly inside the
segment; t‑values outside that range lie on the infinite extension of the line, beyond
its endpoints.
Example: for P₀(1,1), P₁(5,9): P(t) = (1+4t, 1+8t). P(0)=(1,1), P(1)=(5,9), P(0.5)=(3,5), P(0.25)=(2,3) — all inside the segment, while P(−0.3) and P(1.3) fall outside it.
The direction vector of the line is D = P₁ − P₀. Each of the
4 clip‑window boundaries has an outward‑pointing unit normal:
| Boundary | Normal N |
|---|---|
| Left | (−1, 0) |
| Right | (1, 0) |
| Top | (0, 1) |
| Bottom | (0, −1) |
At each boundary intersection, the sign of the dot product between the normal N and the direction D classifies the crossing:
Geometrically: if the angle between N and D is more than 90°, the line is heading into the clip region at that boundary (PE); if less than 90°, it's heading out (PL).
A boundary edge Eᵢ passes through point PEᵢ with outward normal Nᵢ. The
intersection of the line with that edge's infinite extension satisfies
Nᵢ · [P(t) − PEᵢ] = 0. Substituting the parametric
line equation and solving for t gives the general formula:
Applying this formula to each of the 4 axis‑aligned boundaries simplifies to:
| Boundary | t formula |
|---|---|
| Left | t = −(x₀ − xmin) / (x₁ − x₀) |
| Right | t = −(x₀ − xmax) / (x₁ − x₀) |
| Top | t = −(y₀ − ymax) / (y₁ − y₀) |
| Bottom | t = −(y₀ − ymin) / (y₁ − y₀) |
Clip window (0,0)–(300,200). Line: (−250,200) to (150,100), so D = (400,−100).
| Boundary | Nᵢ | Nᵢ·D | t | PE / PL |
|---|---|---|---|---|
| Left | (−1,0) | −400 | 0.625 | PE |
| Right | (1,0) | 400 | 1.375 | PL |
| Bottom | (0,−1) | 100 | 2.0 | PL |
| Top | (0,1) | −100 | 0.0 | PE |
tE = max(0.625, 0.0) = 0.625; tL = min(1.375, 2.0, 1) = 1. Since tE ≤ tL, the visible segment runs from P(0.625) = (0, 137.5) to P(1) = (150, 100).
It fails for concave clip polygons: a line can cross a concave boundary multiple times, producing a PE t‑value that is numerically larger than a PL t‑value (tE > tL) even though part of the line really is visible. The whole segment then gets incorrectly discarded.
| Aspect | Cohen‑Sutherland | Cyrus‑Beck |
|---|---|---|
| Year / Authors | Danny Cohen & Ivan Sutherland | Cyrus & Beck (1978) |
| Underlying math | Boolean logic on region codes | Parametric equations & vector dot products |
| Rectangular window only? | Yes | No — works for any convex shape |
| Handles concave clip regions | N/A (rectangle is always convex) | No — fails on concave polygons |
| Typical use case | Screen/viewport clipping in 2‑D raster systems | General polygon & 3‑D polyhedron clipping |
| Performance sweet spot | Extreme window sizes (very large / very small) | Any convex region, uniform cost per boundary |
Before line clipping, the simplest case is point clipping: a point (x,y) is not clipped (i.e. it is kept) only if it satisfies both range checks:
Otherwise the point is discarded. This same inequality underlies the outcode bits used in Cohen‑Sutherland.
Because rasterized lines approximate a continuous entity with discrete pixel samples, an all‑or‑nothing "each pixel is either colored or left unchanged" approach produces a visible jagged / staircase effect known as aliasing. Antialiasing techniques such as unweighted area sampling reduce this by shading each pixel with an intensity proportional to the percentage of that pixel's tile the ideal line actually covers (e.g. 95%, 75%, 25% coverage in the classic example figure).