Line Drawing, Line Clipping, Polygon Cliping Algorithm
Line Drawing, Line Clipping, Polygon Cliping Algorithm
A line drawing algorithm is a graphical algorithm for approximating a line segment on discrete graphical media. On discrete media, such as pixel-based displays and printers, line drawing requires such an approximation (in nontrivial cases). On continuous media, by contrast, no algorithm is necessary to draw a line. For example, oscilloscopes use natural phenomena to draw lines and curves.
It is assumed here that the points have already been ordered so that x2 > x1. This algorithm works just fine when dx > = dy (i.e., slope is less than or equal to 1), but if dx < dy (i.e., slope greater than 1), the line becomes quite sparse with lots of gaps, and in the limiting case of dx = 0, only a single point is plotted. The nave line drawing algorithm is inefficient and thus, slow on a digital computer. Its inefficiency stems from the number of operations and the use of floating-point calculations. Line drawing algorithms such as Bresenham's or Wu's are preferred instead.
Digital Differential Analyzer (graphics algorithm) Similar to the naive line-drawing algorithm, with minor variations. Bresenham's line algorithm optimized to use only additions (i.e. no divisions or multiplications); it also avoids floating-point computations. Xiaolin Wu's line algorithm can perform anti-aliasing
The endpoints of the line are the pixels at (x0, y0) and (x1, y1), where the first coordinate of the pair is the column and the second is the row. The algorithm will be initially presented only for the octant in which the segment goes down and to the right (x0x1 and y0y1), and its horizontal projection x1 x0 is longer than the vertical projection y1 y0 (the line has a slope whose absolute value is less than 1 and greater than 0.) In this octant, for each column x between x0 and x1, there is exactly one row y (computed by the algorithm) containing a pixel of the line, while each row between y0 and y1 may contain multiple rasterized pixels. Bresenham's algorithm chooses the integer y corresponding to the pixel center that is closest to the ideal (fractional) y for the same x; on successive columns y can remain the same or increase by 1. The general equation of the line through the endpoints is given by:
Since we know the column, x, the pixel's row, y, is given by rounding this quantity to the nearest integer:
The slope (y1 y0) / (x1 x0) depends on the endpoint coordinates only and can be precomputed, and the ideal y for successive integer values of x can be computed starting from y0 and repeatedly adding the slope. In practice, the algorithm can track, instead of possibly large y values, a small error value between 0.5 and 0.5: the vertical distance between the rounded and the exact y values for the current x. Each time x is increased, the error is increased by the slope; if it exceeds 0.5, the rasterization y is increased by 1 (the line continues on the next lower row of the raster) and the error is decremented by 1.0. In the following pseudocode sample plot(x,y) plots a point and abs returns absolute value: function line(x0, x1, y0, y1) int deltax := x1 - x0 int deltay := y1 - y0 real error := 0 real deltaerr := abs (deltay / deltax) deltax != 0 (line is not vertical), // note that this division needs to be done in a way that preserves the fractional part int y := y0 for x from x0 to x1 plot(x,y) error := error + deltaerr if error 0.5 then y := y + 1 error := error - 1.0 // Assume
An extension to the algorithm for circle drawing was presented by Xiaolin Wu in the book Graphics Gems II. Just like the line drawing algorithm is a replacement for Bresenham's line drawing algorithm, the circle drawing algorithm is a replacement for Bresenham's circle drawing algorithm. function plot(x, y, c) is plot the pixel at (x, y) with brightness c (where 0 c 1) function ipart(x) is return integer part of x function round(x) is return ipart(x + 0.5) function fpart(x) is return fractional part of x function rfpart(x) is return 1 - fpart(x) function drawLine(x1,y1,x2,y2) is dx = x2 - x1 dy = y2 - y1 if abs(dx) < abs(dy) then swap x1, y1 swap x2, y2 swap dx, dy end if if x2 < x1 swap x1, x2 swap y1, y2 end if gradient = dy / dx // handle first endpoint xend = round(x1) yend = y1 + gradient * (xend - x1) xgap = rfpart(x1 + 0.5) xpxl1 = xend // this will be used in the main loop ypxl1 = ipart(yend) plot(xpxl1, ypxl1, rfpart(yend) * xgap) plot(xpxl1, ypxl1 + 1, fpart(yend) * xgap) intery = yend + gradient // first y-intersection for the main loop
// handle second endpoint xend = round (x2) yend = y2 + gradient * (xend - x2) xgap = fpart(x2 + 0.5) xpxl2 = xend // this will be used in the main loop ypxl2 = ipart (yend) plot (xpxl2, ypxl2, rfpart (yend) * xgap) plot (xpxl2, ypxl2 + 1, fpart (yend) * xgap) // main loop for x from xpxl1 + 1 to xpxl2 - 1 do plot (x, ipart (intery), rfpart (intery)) plot (x, ipart (intery) + 1, fpart (intery)) intery = intery + gradient end function
CohenSutherland LiangBarsky Fast-clipping CyrusBeck NichollLeeNicholl Fast culling for 2D side-scrolling games Skala O(lg N) Algorithm
CohenSutherland
Main article: CohenSutherland This algorithm divides a 2D space into 9 parts, of which only the middle part (viewport) is visible. The algorithm includes, excludes or partially includes the line based on where the two endpoints are: Both endpoints are in the viewport (bitwise OR of endpoints == 0): trivial accept. Both endpoints are in the same part, which is not visible (bitwise AND of endpoints != 0): trivial reject. Both endpoints are in different parts: In case of this non trivial situation the algorithm finds one of the two points that are outside the viewport (there is at least one point outside). The intersection of the segment and extended viewport border is then calculated (e.g. with the parametric equation for the line) and this new point replaces the outpoint. The algorithm repeats until a trivial accept or reject occurs.
[edit]LiangBarsky Main article: LiangBarsky The LiangBarsky algorithm uses the parametric equation of a line and inequalities describing the range of the clipping box to determine the intersections between the line and the clipping box. With these intersections it knows which portion of the line should be drawn. This algorithm is significantly more efficient than CohenSutherland, but Cohen-Sutherland does trivial accepts and rejects much faster, so it should be considered instead if most of the lines you need to clip would be completely in or out of the clip window. [edit]CyrusBeck Main article: CyrusBeck algorithm Very similar to Liang-Barsky algorithm. The difference is that Liang-Barsky is a simplified Cyrus-Beck variation that was optimized for a rectangular clip window.
The Cyrus-Beck algorithm is of O(N) complexity, and it is primarily intended for a clipping a line in the parametric form against a convex polygon in 2 dimensions or against a convex polyhedra in 3 dimensions.[1] [edit]NichollLeeNicholl Main article: NichollLeeNicholl The Nicholl-Lee-Nicholl algorithm is a fast line clipping algorithm that reduces the chances of clipping a single line segment multiple times, as may happen in the Cohen-Sutherland algorithm. [edit]Fast
clipping
This algorithm has similarities with Cohen-Sutherland. The start and end positions are classified by which portion of the 9 area grid they occupy. A large switch statement jumps to a specialized handler for that case. In contrast, Cohen-Sutherland may have to iterate several times to handle the same case.[2] [edit]O(lg
N) algorithm
This algorithm classifies vertices against the given line in the implicit form p: ax+by+c=0. As the polygon is assumed to be convex and vertices are ordered clockwise or anti-clockwise binary search can be applied and leads to a O(lg N) run time complexity.[3] [edit]Skala Main article: Skala algorithm This algorithm is based on homogeneous coordinates and duality.[4] It can be used for line or line segment clipping against a rectangular window as well as against a convex polygon. The algorithm is based on classifying a vertex of the clipping window against a half-space given by a line p: ax+by+c=0. The result of the classification determines the edges intersected by the line p. The algorithm is simple, easy to implement and extensible to a convex window as well. The line or line segment p can be computed from points x1, x2 given in homogeneous coordinates directly using the cross product as p = x1 x x2 = [x1,y1,w1] x [x2,y2,w2] or as p = x1 x x2 = [x1,y1,1] x [x2,y2,1] if given in the Euclidean coordinates.
SutherlandHodgman algorithm
The SutherlandHodgman algorithm is used for clipping polygons. It works by extending each line of the convex clip polygon in turn and selecting only vertices from the subject polygon that are on the visible side. The algorithm begins with an input list of all vertices in the subject polygon. Next, one side of the clip polygon is extended infinitely in both directions, and the path of the subject polygon is traversed. Vertices from the input list are inserted into an output list if they lie on the visible side of the extended clip polygon line, and new vertices are added to the output list where the subject polygon path crosses the extended clip polygon line. This process is repeated iteratively for each clip polygon side, using the output list from one stage as the input list for the next. Once all sides of the clip polygon have been processed, the final generated list of vertices defines a new single polygon that is entirely visible. Note that if the subject polygon was concave at vertices outside the clipping polygon, the new polygon may have coincident (i.e. overlapping) edges this is acceptable for rendering, but not for other applications such as computing shadows.
Pseudo code
Given a list of edges in a clip polygon, and a list of vertices in a subject polygon, the following procedure clips the subject polygon against the clip polygon. List outputList = subjectPolygon; for (Edge clipEdge in clipPolygon) do List inputList = outputList; outputList.clear(); Point S = inputList.last; for (Point E in inputList) do if (E inside clipEdge) then if (S not inside clipEdge) then outputList.add(ComputeIntersection(S,E,clipEdge)); end if outputList.add(E); else if (S inside clipEdge) then outputList.add(ComputeIntersection(S,E,clipEdge)); end if S = E; done done
The vertices of the clipped polygon are to be found in outputList when the algorithm terminates. Note that a point is defined as being inside an edge if it lies on the same side of the edge as the remainder of the polygon. If the vertices of the clip polygon are consistently listed in a clockwise direction, then this is equivalent to testing whether the point lies to the left of the line (left means inside, while right means outside), and can be implemented simply by using a cross product. ComputeIntersection is a trivial function, omitted here for clarity, which returns the intersection of a line segment and an infinite edge. Note that it is only called if such an intersection is known to exist, and hence can simply treat both lines as being infinitely long.
3. A and B do not overlap - return None for clipping or A & B for merging.
A list of inbound intersections is then generated. Each intersection in the list is then followed clockwise around the linked lists until the start position is found. One or more concave polygons may produce more than one intersecting polygon. Convex polygons will only have one intersecting polygon. The same algorithm can be used for merging two polygons by starting at the outbound intersections rather than the inbound ones. However this can produce counter-clockwise holes. Some polygon combinations may be difficult to resolve, especially when holes are allowed. Points very close to the edge of the other polygon may be considered as both in and out until their status can be confirmed after all the intersections have been found and verified, however this increases the complexity.