510 likes | 718 Views
Raster Display Model. Pixel (Picture Element, 像素 ). 選最接近線的 pixels?. Scan Conversion Lines. DDA (Digital Differential Analyzer) Bresenham Algorithm Midpoint Algorithm Double-step Algorithm. /* x0 <= x1 and y0 <= y1 */ void Line (x0,y0,x1,y1,c) int x0,y0,x1,y1,c; {
E N D
Raster Display Model Pixel (Picture Element, 像素)
選最接近線的pixels? Scan Conversion Lines • DDA (Digital Differential Analyzer) • Bresenham Algorithm • Midpoint Algorithm • Double-step Algorithm
/* x0 <= x1 and y0 <= y1 */ void Line (x0,y0,x1,y1,c) int x0,y0,x1,y1,c; { float m = (y1-y0)/(x1-x0), y = y0; int x; for (x = x0; x <= x1; x++){ WritePixel(x,round(y),c); y += m; } } DDA Line-Drawing Algorithm Drawback: floating-point arithmetic
Midpoint Algorithms where where (都是整數)
Decision variable: Midpoint Algorithms
What about 瞭解了為什麼定義
// Midpoint algorithm for drawing lines // with x0 <= x1 and y0 <= y1. // Line(int x0,int y0,int x1,int y1,int c) { int dx = x1-x0, dy = y1-y0; int incrE = 2*dy, incrNE = (dy-dx)*2; int d = 2*dy-dx; int y = y0; for (int x = x0; x <= x1; x++) { WritePixel(x,y,c); if (d <= 0) { d += incrE;} // choose E else { d += incrNE; y++; } // choose NE } }
void CirclePoints(x,y,c) int x,y,c; { WritePixel(x,y,c); WritePixel(y,x,c); WritePixel(y,-x,c); WritePixel(x,-y,c); WritePixel(-x,-y,c); WritePixel(-y,-x,c); WritePixel(-y,x,c); WritePixel(-x,y,c); } Scan Converting Circles 8-way Symmetry
Consider the second octant E SE i i+1 i+2
E is chosen E SE i i+1 i+2
SE is chosen E SE i i+1 i+2
// The Midpoint Algorithm for drawing // circles with the center at the origin // and the radius equal to R. void Circle (int R, int c) { int i = 0, j = R, d = 1 - R; CirclePoint(i,j,c); while (i<j) if (d < 0) d += i*2+3; // Select E else { d += (i-j)*2+5; j--; } // Select SE i++; CirclePoint(i,j,c); } }
Decide • which pixels to fill • what value to fill them Filling Polygons exterior boundary interior We will discuss: (A). Fill solid color: (1) Scan-line algorithm (2) Seed-filling algorithm (B). Fill patterns
for (x = xmin; x <= xmax; x++) for (y = ymin; y <= ymax; y++) WritePixel(x,y,c); rectangle: ymax ymin xmin xmax Do not write pixels on shared edge twice! shared edge
basic idea: A: (2,3) B: (7,1) C: (14,5) D: (14,11) E: (7,7) F: (2,9) 12 D F 10 8 E 6 C 4 A B 2 2 4 6 8 10 12 14 vertices list 2 7 14 14 7 2 x y 3 1 5 11 7 9 A B C D E F polygons: • draw those pixels strictly interior to the region. • use scan lines. • spatial coherence. • span coherence • scan-line coherence • edge coherence
c-a d-b a d min 1/m max next x y -5 2 6 4 6 4 data structures (1) Edge data structure: (c,d) (a,b) (2) Edge Table (ET): l 9 l 8 EF DE l 7 9 7 11 7 l 6 CD 5 l 0 11 13 l 4 FA 3 l 0 9 2 l 2 AB BC l 1 3 7 5 7 l 0 increasing x coorinate y
12 D 10 8 F E 6 C 4 A B 2 2 4 6 8 10 12 14 -5 2 6 4 max y 6 4 (3) Active Edge Table (AET): a data structure that keeps track of the set of edges the scan line intersects and the intersection points. AET pointer EF DE CD FA l 9 2 11 10 0 0 11 13 9 2 x 1/m scan line 9 (increasing x order) AET pointer DE CD l 11 12 0 11 13 scan line 10
Edge Coherence j y+4 y+3 y+2 y+1 y (m: slope, m ?0,m ?*) 1/m // program for calculating the // intersection points of an edge // and a scan line. x = xmin; for (y = ymin; y <= ymax; y++) { output(x,y); x += 1/m; }
odd-parity rule 0 1 2 3 4 5 6 special cases: (1). intersections not at the grid: (2). intersections at the grid: interior exterior
G F H I E J D C A B (3). intersections are at the grid and are shared vertices: F We count the ymin vertex of an edge in the parity calculation but not the ymax vertex; therefore, a ymax vertex is drawn only if it is the ymin vertex for the adjacent edge. (4). horizontal edges: We do not count the vertices of a horizontal edge when calculating parity. 範例:(assume that all vertices are at the grid) G F H I E J D C A B
Outline of the algorithm for filling polygons with solid color 1. Build ET and initialize AET to be empty. 2. Set y to the smallest y coordinate that has an entry in the ET, i.e., y for the first nonempty bucket. 3. Repeat until the AET and ET are empty: 3.1 Move from ET bucket y to the AET those edges whose ymin = y, then sort the AET on x (merge sort). 3.2 Fill in desired pixel values on scan line y by using pairs of x coordinate from the AET (odd-parity rule). 3.3 Remove from the AET those edges for which y = ymax. 3.4 Increment y by 1 (set it to the next scan line). 3.5 For each nonvertical edge remaining in the AET, update x for the new y (edge coherence).
seed Seed filling Seed filling is used to fill areas defined pixels on the screen which form a bounded region. It works for a closed area of any shape.
int bndColor, fillColor; void seed_fill (int x, int y) { int pixColor = ReadPixel(x,y); if (pixColor != bndColor && pixColor != fillColor ) { WritePixel(x,y,fillColor); seed_fill(x+1,y); seed_fill(x-1,y); seed_fill(x,y+1); seed_fill(x,y-1); } } Drawbacks: • recursive calls are expensive. • redundant checking of filling pixels. • the case of out of screen is not handled.
transparent mode: bit is 1 * WritePixel with foreground color. bit is 0 * do not WritePixel. • opaque mode: bit is 1 * WritePixel with foreground color. bit is 0 * WritePixel with background color. Pattern Filling bitmap ideas:
anchor point of bitmap: 1. put the left-top pixel of the bitmap on some vertex. 優點: the pattern is stick to the primitive, so when the primitive is moved the pattern remains the same. 2. Use the left-top corner of the bounding rectangle of the primitive as the anchor point. 優點:easy to implement and the pattern is not dependent on the location. 缺點:need to calculate the bounding rectangle.
3. Consider the entire screen is being tiled with the pattern and think of the primitive as consisting of an outline or filled area of transparent bits that let the pattern show through. 優點:easy to implement. 缺點:the pattern is dependent on the location. SRGP uses this method. Suppose that the bitmap is an M by N array of bits. Then we can use the following code to write pixel: if (pattern[x%M,y%N]) WritePixel(x,y,value);
Thick Primitives • Replicating Pixels:
Moving Pen (Fat Pen): • Filling area:
A A before clipping after clipping Clipping(剪裁) • clipping before scan conversion: * calaulate intersection points first. * suitable for simple primitives such as lines, rectangles, and polygons. • scissoring (clipping during scan conversion): * write only pixels in the clipping region. * need quick bound checking. • brute force method: * generate the entire collection of primitives into a temporary canvas and then copy only the contents of the clip rectangle to the destination canvas * mostly used to generate text.
y max y min x x min max Clipping Lines • Cohen-Sutherland Algorithm • Parametric Line Clipping Algorithm 1. Determine whether a point is in the clipping rectangle (x,y)
Types of Intersection: D F D’ D’ C C E H B B H’ H’ A A G’ G’ G • trival acception Both endpoints are inside the clipping rectangle such as the line AB. • no intersections (line EF) • intersect with one edge (line CD) • intersect with two edge (line GH)
D F D’ C E H B H’ A J G’ J’ G I’ I 直覺作法: 若非簡單被接受的線(如AB),則逐一檢查該線是否和 clipping rectangle 的四條邊線段相交。做法如下: 1. 計算該線和上圖中四條邊線的交點。 2. 檢查交點是否落於方塊內。 3. 若某一交點在方塊內,則將該交點變為新的 線段端點(如 CD 和 GH)。 4. 若交點全在方塊外,則該線落在方塊外 (如 IJ)。 缺點:計算量大,沒有效率。
Cohen-Sutherland Algorithm D C F G E B A H J I 概念: 1. trivial rejection: 假定線段的兩個端點座標分別為(x1,y1) 和(x2,y2), 則當下列任一條件滿足時,此線段必不在方塊內:
1001 1000 1010 0001 0000 0010 0101 0100 0110 技巧: region codes: 1: true, 0: false F If the logical and of the codes of the endpointsis not zero, the line can be trivially rejected; otherwise, we need further checking. typedefstruct { unsigned all; unsigned left:1; unsigned right:1; unsigned bottom:1; unsigned top:1; } outcode; outcode CompCode (float x, float y, float xmin, float xmax, float ymin, float ymax) { outcode code; code.all = 0; if (y > ymax) { code.top = 1; code.all += code.top; } elseif (y < ymin) { code.bottom = 1; code.all += code.bottom; } else if (x > xmax) { code.right = 1; code.all += code.right; } else if (x < xmin) { code.left = 1; code.all += code.left; } return code; }
J D I C B H A G F E 2. subdividing iteration: 若無法簡單判斷線段是在方塊內或外,則將之切分為兩段 (以和邊線的交點為切分點,如C或F)。那麼,其中必有 一段落在方塊外,因此可以截去該段。剩下來的那段,我 們重複以上動作直到可以簡單判斷是在方塊內或外。 範例: (1) (2) (3) (4)
void CS_LineClipDraw (float x0, float y0, float x1, float y1, float xmin, float xmax, float ymin, float ymax) { float m = (y1 - y0) / (x1 - x0); // the slope boolean accept = FALSE; outcode outcode0, outcode1, outcodeOut; float x, y; outcode0 = CompOutCode(x0,y0,xmin,xmax,ymin,ymax); outcode1 = CompOutCode(x1,y1,xmin,xmax,ymin,ymax); do { if (outcode0.all == 0 && outcode1.all == 0) { accept = TRUE; break; } if (outcode0.all & outcode1.all != 0) break; // reject outcodeOut = (outcode0.all != 0)? outcode0 : outcode1; if (oucodeOut.top) { x = x0 + (ymax - y0) / m; y = ymax; } elseif (outCodeOut.bottom) { x = x0 + (ymin - y0) / m; y = ymin; } elseif (outcodeOut.right) { y = y0 + (xmax - x0) * m; x = xmax; } else // outcodeOut.left is 1 { y = y0 + (xmin - x0) * m; x = xmin; } if (outcodeOut.all == outcode0.all) { x0 = x; y0 =y; outcode0 = CompOutCode(x0,y0,........); } else { x1 = x; y1 =y; outcode1 = CompOutCode(x1,y1,........); } } while (TRUE); if (accept) DrawLine(x0, y0, x1, y1); // floating-point version }
Sutherland-Hodgman Algorithm stratege: divide and conquer.
input polygon: vertex list output polygon: vertex list for each edge of check which case in the following holds. inside outside inside outside s p (output) s p clipping edge i: output clipping edge inside outside inside outside p: second output p s i: first output s clipping edge clipping edge (no output)
Implementation: typedef struct vertex { float x, y; } vertex; typedef vertex edge[2]; typedef struct polygon { unsigned nVertex; vertex *vertexArray; } polygon; data structures: 1. 計算交叉點; vertex Intersect (vertex s, vertex p, edge clipBnd) { float m = (p.y - s.y)/(p.x - s.x); vertex intersectPt; if (clipBnd[0].y == clipBnd[1].y) { // a horizontal clipping edge. intersectPt.y = clipBnd[0].y; intersectPt.x = s.x + (clipBnd[0].y-s.y)/m; } else { // a vertical clipping edge. intersectPt.x = clipBnd[0].x; intersectPt.y = s.x + (clipBnd[0].x-s.x)*m; } return intersetPt; }
2. 決定多面體端點是在切割邊線的內或外; top D C v left right A B bottom boolean Inside (vertex v, edge clipBnd) { if (clipBnd[1].x > clipBnd[0].x) // bottom if (v.y >= clipBnd[0].y) return TRUE; if (clipBnd[1].x < clipBnd[0].x) // top if (v.y <= clipBnd[0].y) return TRUE; if (clipBnd[1].y > clipBnd[0].y) // right if (v.x <= clipBnd[1].x) return TRUE; if (clipBnd[1].y < clipBnd[0].y) // left if (v.x >= clipBnd[1].x) return TRUE; return FALSE; }
void SH_clipPolygon_upon_one_bnd ( polygon in, // input polygon polygon out, // clipped polygon egde clipBnd // clipping boundary ) { vertex s, p; int i = 0, j; s = in.vertexArray[in.nVertex-1]; for (j = 0; j < in.nVertex; j++) { p = in.vertexArray[j]; if (Inside(p, clipBnd)) if (Inside(s, clipBnd)) // case 1 out.VertexArray[i++] = p; else { // case 4 out.VertexArray[i++] = Intersect(s,p,clipBnd); out.VertexArray[i++] = p; } else if (Inside(s, clipBnd)) // case 2 out.VertexArray[i++] = Intersect(s,p,clipBnd); // no action for case 3 s = p; } out.nVertex = i; } 例: 1 1
h Generating Characters (產生字元) 定義字形的兩種方式: 1. bitmap fonts 2. outline fonts 1. bitmap fonts: font table (font cache): 利用vedio memory 剩餘的部份 儲存常用字形。
typedef struct charLocation { int leftX; // horizontal position int width; // width of image } charLocation; totalHeight descend width leftX typedef struct fontCacheDescriptor { int cache; // canvas id int descenderHeight; int totalHeight; int interCharacterSpacing; charLocation locationTable[128]; } fontCacheDescriptor;
Yes, please go. void SRGP_characterText ( point origin, // the starting location for printing string char *stringToPrint, fontCacheDescriptor fontInfo ) { rectangle fontCacheRect; char charToPrint; int i; charLocation *fp; origin.y -= fontInfo.descenderHeight; // match the anchor point for (i = 0; i < strlen(stringToPrint); i++) { charToPrint = stringToPrint[i]; fp = &fontInfo.locationTable[charToPrint]; fontCacheRect.bottomLeft = SRGP_defPoint(fp->leftX, 0); fontCacheRect.topRight = SRGP_defPoint(fp->leftX+fp->width-1, fontInfo.totalHeight-1); SRGP_copyPixel(fontInfo.cache, fontCacheRect, origin); origin.x += fp->width + fontInfo.interCharacterSpacing; } } 優點: 簡單、速度快。 缺點: 當使用字型多時,非常耗用記憶體。 size, face (normal, bold, italic)
是否有方法僅使用一個字形定義即可據以 產生不同尺寸的字型? 外框 內框 1. 利用數學曲線描述字的內外框形狀。 2. 將字的內外框所夾的區域填滿。 2. 若需要不同尺寸的字,則用數學公式將內外框 放大或縮小,然後填滿其間。
數學曲線用以定義字形: 1. Bezier curves (eg., TrueType font, TeX CM fonts); 2. B-spline curves (eg., PostSrcipt fonts). 優點: 可以產生各種大小的字型。 對需要各種大小字形的系統而言,可以節省 記憶體。 缺點: 1. 若不需要太多不同大小字型,可能更浪費 記憶體。 2. 因為每次必須掃描產生字型,速度因此較慢。 3. 產生之字型可能比相對應之bitmap字型較不 美觀。 折衷方案: 用outline方式儲存字型,當需要時將其轉換成bitmap形 式存在font cache中,以加快字型產生。