Giải quyết trường hợp dịng quét đi ngang qua đỉnh

Một phần của tài liệu Giáo trình Đồ họa máy tính (Trang 41 - 50)

2. CÁC THUẬT TỐN VẼ ĐƯỜNG

3.1.3. Giải quyết trường hợp dịng quét đi ngang qua đỉnh

Người ta đưa ra quy tắc sau để tính số giao điểm khi dịng quét đi ngang qua đỉnh :

•Tính một giao điểm nếu chiều của hai cạnh kề của đỉnh đĩ cĩ xu hướng tăng hay giảm.

•Tính hai giao điểm nếu chiều của hai cạnh kề của đỉnh đĩ cĩ xu hướng thay đổi, nghĩa là tăng-giảm hay giảm-tăng.

Hình 2.22 – Quy tắc tính một giao điểm (a) và hai giao điểm (b)

Khi cài đặt để khỏi phải xét điều kiện này cho phức tạp, khi xây dựng dữ liệu cho mỗi cạnh trước khi đưa vào ET, người ta sẽ xử lí các cạnh cĩ đỉnh tính hai giao điểm bằng cách loại đi một pixel trên cùng của một trong hai cạnh như hình 2.23 :

Hình 2.23 – Cạnh được lưu trong ET chỉ là

Cài đặt minh họa sau sử dụng chung một danh sách EDGELIST cho cả ET và AET. AET được quản lí nhờ vào hai con trỏ FirstId và LastId.

Cài đặt minh họa thuật tốn tơ màu scan-line #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <graphics.h> #include <dos.h> #define MAXVERTEX 20 #define MAXEDGE 20 #define TRUE 1 #define FALSE 0 typedef struct { int x; int y; }POINT; typedef struct{ int NumVertex; POINT aVertex[MAXVERTEX]; }POLYGON; typedef struct { int NumPt; float xPt[MAXEDGE]; }XINTERSECT; typedef struct {

int yMin; // Gia tri y nho nhat cua 2 dinh

float xIntersect; // Hoanh do giao diem cua canh & dong quet float dxPerScan; // Gia tri 1/m

int DeltaY; }EDGE; typedef struct { int NumEdge; EDGE aEdge[MAXEDGE]; }EDGELIST; /*

Dat 1 canh vao danh sach canh.

Cac canh duoc sap theo thu tu giam dan cua yMin (yMin la gia tri y lon nhat cua 2 dinh 1 canh)

Xu li luon truong hop dong quet di ngang qua dinh ma tai do chi tinh 1 diem giao

*/

void PutEdgeInList(EDGELIST &EdgeList, POINT p1, POINT p2, int NextY) { EDGE EdgeTmp; EdgeTmp.dxPerScan = float(p2.x-p1.x)/(p2.y-p1.y); // 1/m if(p1.y < p2.y) { /*

Truong hop dong quet di ngang qua dinh la giao diem cua 2 canh co huong y cung tang

*/if(p2.y < NextY) if(p2.y < NextY) { p2.y--; p2.x -= EdgeTmp.dxPerScan; } EdgeTmp.yMin = p1.y; EdgeTmp.xIntersect= p1.x; EdgeTmp.DeltaY = abs(p2.y-p1.y)+1; } // if else { /*

Truong hop dong quet di ngang qua dinh la giao diem cua 2 canh co huong y cung giam

*/if(p2.y > NextY) if(p2.y > NextY) { p2.y++; p2.x+= EdgeTmp.dxPerScan; } EdgeTmp.yMin = p2.y; EdgeTmp.xIntersect= p2.x;

EdgeTmp.DeltaY = abs(p2.y-p1.y)+1;

}//else

// xac dinh vi tri chen int j = EdgeList.NumEdge;

while((j>0) && (EdgeList.aEdge[j-1].yMin>EdgeTmp.yMin)) {

EdgeList.aEdge[j] = EdgeList.aEdge[j-1]; j--;

}

// tien hanh chen dinh moi vao canh

EdgeList.NumEdge++;

EdgeList.aEdge[j] = EdgeTmp;

} // PutEdgeInList

/*

Tim dinh ke tiep sao cho khong nam tren cung duong thang voi dinh dang xet

*/

int FindNextY(POLYGON P, int id) { int j = (id+1)%P.NumVertex; while((j<P.NumVertex)&&(P.aVertex[id].y == P.aVertex[j].y)) j++; if(j<P.NumVertex) return (P.aVertex[j].y); return 0;

} // FindNextY

// Tao danh sach cac canh tu polygon da cho

void MakeSortedEdge(POLYGON P, EDGELIST &EdgeList, int &TopScan, int &BottomScan)

{

TopScan = BottomScan = P.aVertex[0].y; EdgeList.NumEdge = 0;

for(int i=0; i<P.NumVertex; i++) {

// Truong hop canh khong phai la canh nam ngang if(P.aVertex[i].y != P.aVertex[i+1].y)

PutEdgeInList(EdgeList, P.aVertex[i], P.aVertex[i+1], FindNextY(P, i+1));

//else Xu li truong hop canh nam ngang if(P.aVertex[i+1].y > TopScan)

TopScan = P.aVertex[i+1].y;

}

BottomScan = EdgeList.aEdge[0].yMin;

} //MakeSortedEdge

// Cap nhat lai hai con tro FirstId, LastId cho biet danhsach cac canh active

void UpdateActiveEdgeList(EDGELIST EdgeList, int yScan, int &FirstId, int &LastId)

{

while((FirstId<EdgeList.NumEdge-1) &&(EdgeList.aEdge[FirstId].DeltaY == 0))

FirstId++;

LastId++;

} // UpdateActiveEdgeList

void SortOnX(XINTERSECT & aIntersectPt) {

for(int i=0; i<aIntersectPt.NumPt-1; i++) {

int Min = i, t;

for(int j=i+1; j<aIntersectPt.NumPt; j++) if( aIntersectPt.xPt[j] < aIntersectPt.xPt[Min])

Min = j; t = aIntersectPt.xPt[Min]; aIntersectPt.xPt[Min] = aIntersectPt.xPt[i]; aIntersectPt.xPt[i] = t; } } // SortOnX /*

Tim cac hoanh do giao diem cua cac canh cua da giac voi dong quet yScan. Sau khi tim cac hoanh do giao diem, ta sap xep lai theo chieu tang cua x

*/

void FindXIntersection(EDGELIST EdgeList, XINTERSECT &aIntersectPt, int

FirstId, int LastId)

{

aIntersectPt.NumPt = 0;

for(int i=FirstId; i<=LastId; i++) {

if(EdgeList.aEdge[i].DeltaY>0) { aIntersectPt.xPt[aIntersectPt.NumPt] = EdgeList.aEdge[i].xIntersect; aIntersectPt.NumPt++; } } SortOnX(aIntersectPt); } //FindXIntersection

#define Round(x) int(x+0.5)

void FillLine(XINTERSECT aIntersectPt, int yScan) {

for(int i=0; i<aIntersectPt.NumPt; i+=2)

line(Round(aIntersectPt.xPt[i]), yScan, Round(aIntersectPt.xPt[i+1]), yScan);

} // FillLine

void UpdateEdgeList(EDGELIST &EdgeList,int FirstId,int LastId) {

for(int i=FirstId; i<=LastId; i++) { if(EdgeList.aEdge[i].DeltaY>0) { EdgeList.aEdge[i].DeltaY--; EdgeList.aEdge[i].xIntersect += EdgeList.aEdge[i].dxPerScan; } }

} //FillLine

void ScanLineFill(POLYGON P) {

EDGELIST EdgeList; XINTERSECT aIntersectPt;

int TopScan, BottomScan, FirstId, LastId;

MakeSortedEdge(P, EdgeList, TopScan, BottomScan); FirstId = LastId = 0;

for(int i=BottomScan; i<=TopScan; i++) {

// Cap nhat lai danh sach cac canh active -

tuc la cac canh cat dong quet i

UpdateActiveEdgeList(EdgeList, i, FirstId, LastId);

// Tim cac hoanh do giao diem cua dong

quet voi cac canh cua da giac va sap xep lai cac hoanh do giao diem truc tiep tren EdgeList

FindXIntersection(EdgeList, aIntersectPt, FirstId, LastId);

FillLine(aIntersectPt, i);

UpdateEdgeList(EdgeList, FirstId, LastId);

}

} //ScanLineFill

Một phần của tài liệu Giáo trình Đồ họa máy tính (Trang 41 - 50)