BAB-9
POLIGON dan KURVA
Poligon adalah bentuk yang disusun dari serangkian garis. Kurva
Bezier digunakan untuk membentuk garis lengkung menggunakan
algoritma Biezer.
By: I Gusti Ngurah Suryantara, S.Kom., M.Kom
9.1. PENDAHULUAN
Poligon adalah bentuk yang disusun dari serangkaian garis. Gambar 9.1 memperlihatkan
beberapa bentuk poligon. Titik sudut dari poligon disebut vertex sedangkan gar
is
penyusun poligon disebut edge.
116
(a). 4-Koneksi
(b). 8-Koneksi
118
Grafika Komputer Pertemuan Ke-10
9.3. KURVA
Kali ini kita akan mempelajari bagaimana membuat kurva menggunakan algoritm
a
Bezier. Algoritma membuat kurva bezier diusulkan oleh seorang ahli mesin dari perancis
yang bekerja di perusahaan Renault dan digunakan untuk merancang badan mobil.
9.3.1. Kurva Bezier
Kita sudah mempelajari bagaimana membentuk garis lurus, seperti dengan menggunakan
algoritma DDA dan algoritma Bresenham. Pada bab ini kita akan membahas pembuatan
kurva. Pembuatan kurva yang akan dibahas dengan menggunakan algoritma yan
g
diusulkan oleh Bezier.
Pierre Bezier seorang ahli mesin perancis yang bekerj
a
diperusahaan renult. Bezier lahir pada tanggal 1 September
1910 dan meninggal pada tgl 25 Novmber 1999. Bezie
r
memperoleh gelar dalam bidang mekanikal dari Ecol
e
Nationale Superieure dSeni et Metiers tahun 1930. Gelar
kedua dibidang elektro pada tahun 1931 di Ecole Superieure
dElectricite, dan doktor pada tahun 1977 bidang matematik
dari Universitas Paris. Ia bekerja untuk renult dari 1933-1975,
di mana dia mengembangkan UNISURF USD CAM sistem.
Dari tahun 1958-1979 dia profesor produksi di tekni
k
konservatori nasional et des seni metiers. Pada tahun 1985 ia
telah diakui oleh ACM SIGGRAPH dengan Steven A Coons
atas kontribusi untuk komputer grafis dan teknik interaktif.
KURVA BZIER
Kurva Bezier disusun dari n+1 titik kontrol dan bentuk kurval diperoleh sebagai hasil dari
perhitungan fungsi polinomial yang dibentuk dari koordinat titik kontrol. Koordinat titik
kurva diperoleh dengan persamaan.
n
P(u) =
pB
k k,n(u)
rumus 1
k=0
Setiap Bk,n(u) merupakan fungsi polinomial yang didefinisikan sebagai rumus 2 dan u
bergerak dari 0 ke 1 serta pk menyatakan koordinat dari titik kontrol ke k. Pertambahan
nilai u akan menentukan kehalusan kurva.
k
n-k
rumus 2
rumus 3
xk Bk,n (u)
k=0
n
y(u) =
yk Bk,n (u)
rumus 4
k=0
Salah satu kelemahan kurva Bezier adalah kurva yang dihasilkan tidak dapat secara ketat
mengikuti bentuk dari titik kontrol sehingga
bila
n-k dapat merepotkan
k
n-k kita ingin membuat
(u) = membutuhkan
C(n,k)u (1-u) titik
= -----------u lokasinya
(1-u)
bentuk kurva tertentuBkn
karena
kontrol yang
berjauhan.
LATIHAN
Hitung (x,y) koordinat kurva bezier yang memiliki 4 titik kontrol yaitu p0(0,0), p1(1,2),
p2((3,3) dan p3(4,0).
JAWAB
Untuk empat point kontrol, n = 3
Langkah pertama hitung seluruh fungsi blending, Bkn untuk k-0,...,n menggunaka
n
rumus:
n!
k
k!. (n-k)!
3!
0
3
0
3
3
B03(u) = -------- u (1-u) = 1.u (1-u) = (1 u)
0! . 3!
3!
1
2
1
2
2
B13(u) = -------- u (1-u) = 3.u (1-u) = 3u.(1 u)
1! . 2!
3!
120
Grafika Komputer Pertemuan Ke-10
Kita dapat melihat bahwa fungsi-fungsi ini sangat sederhana. Semuanya ini identik untuk
semua belokan pada kurva bezier dengan p titik kontrol. Sekarang kita siap unt
uk
menghitung pada point melengkung. Parameter u selalu mengalami perubahan dari 0
sampai dengan 1. u = 0 berkitan dengan titik awal lengkungan (titik kontrol pertama); u1
berkaitan dengan titik akhir lengkungan (titik kontrol terakhir). Kita hanya memutuskan
pada jumlah langkah-langkah anara nilai 0 samapi 1, dan dari nilai untuk menghitun
g
peningkatan Du, yang 1/ (jumlah langkah 1). Makin besar (banyak) jumlah langkahlangkah yang dikerjakan kurva makin halus akan tetapi semakin lambat dalam proses
perhitungan (menggambar).
Pada contoh ini jumlah langkah yang harus dikerjakan sebanyak 6, maka du =1 / (6-1) =
1/5 = 0,2. 0,2 sebagi nilai steps yang bergerak dai 0.0, 0.2, 0.4 s/d 1. Dengan 6 langkah
belokan (lengkung) akan memiliki 6 koordinat. Kordinat-kordinat yang dihasilkan akan
digabung dengan segmen garis.
Mari kita menghitung titik kontrol berdasarkan algoritma yang sederhana ini.
121
Grafika Komputer Pertemuan Ke-10
122
Grafika Komputer Pertemuan Ke-10
Dim u As Single
Dim B(0 To 3) As Single
Dim Q() As POINTAPI
'calculate Bezier curve
' Steps = Form1.SlidNilaiU.Value
ReDim Q(0 To Steps)
For i = 0 To Steps
u = i / Steps
'Bernstein cubic polynomials
123
Grafika Komputer Pertemuan Ke-10
B(0)
B(1)
B(2)
B(3)
=
=
=
=
(1 u) ^ 3
3 * u * (1 u) ^ 2
3 * u ^ 2 * (1 u)
u ^ 3
For j = 0 To 3
Q(i).X = Q(i).X + P(j).X * B(j)
Q(i).Y = Q(i).Y + P(j).Y * B(j)
Next j
Form1.ListView2.ListItems.Add , , Format(u, "0.##")
Form1.ListView2.ListItems(Form1.ListView2.ListItems.Count).SubItems(1)
= Q(i).X
Form1.ListView2.ListItems(Form1.ListView2.ListItems.Count).SubItems(2)
= Q(i).Y
Next i
'draw Bezier curve
Canvas.CurrentX = Q(0).X
Canvas.CurrentY = Q(0).Y
For i = 0 To Steps
Canvas.Line (Canvas.CurrentX, Canvas.CurrentY)(Q(i).X, Q(i).Y)
Next i
End Function
124
Grafika Komputer Pertemuan Ke-10
//the stack
#define stackSize 16777216
int stack[stackSize];
int stackPointer;
//the auxiliary functions
bool paint_drawLine(int x1, int y1, int x2, int y2, ColorRGB color);
void clearScreenBuffer(ColorRGB color);
//the graphics buffer
#define screenW 256
#define screenH 256
Uint32 screenBuffer[screenW][screenH];
int main(int argc, char *argv[])
{
screen(screenW, screenH, 0, "Flood Fill");
clearScreenBuffer(RGB_White);
int mouseX, mouseY;
int oldMouseX, oldMouseY;
bool LMB, RMB;
while(!done())
{
oldMouseX = mouseX;
oldMouseY = mouseY;
getMouseState(mouseX, mouseY, LMB, RMB);
//3 different mouse input actions
if(LMB) paint_drawLine(oldMouseX, oldMouseY, mouseX, mouseY,
RGB_Black);
if(RMB)
{
Uint32 color = RGBtoINT(ColorRGB((mouseX % 3 + 1) * 64,
(mouseY % 8) * 32, (mouseX + mouseY) % 256));
floodFillScanlineStack(mouseX, mouseY, color,
screenBuffer[mouseX][mouseY]);
}
if(RMB && LMB) clearScreenBuffer(RGB_White);
//benchmark
readKeys();
if(inkeys[SDLK_SPACE])
{
float startTime = getTime();
for(int i = 1; i <= 50; i++) floodFill4Stack(mouseX,
mouseY, RGBtoINT(ColorRGB(i,255,i)), screenBuffer[mouseX][mouseY]);
float endTime = getTime();
125
Grafika Komputer Pertemuan Ke-10
fprint(endTime2 startTime2, 0, 0, 8, RGB_Black, 1,
RGB_White);
redraw();
sleep();
}
//redraw the screen each frame
drawBuffer(screenBuffer[0]);
redraw();
}
return 0;
}
///////////////////////////////////////////////////////////////////////
//Stack Functions
///////////////////////////////////////////////////////////////////////
bool pop(int &x, int &y)
{
if(stackPointer > 0)
{
int p = stack[stackPointer];
x = p / h;
y = p % h;
stackPointer;
return 1;
}
else
{
return 0;
}
}
bool push(int x, int y)
{
if(stackPointer < stackSize 1)
{
stackPointer++;
stack[stackPointer] = h * x + y;
return 1;
}
else
{
return 0;
}
}
void emptyStack()
{
int x, y;
while(pop(x, y));
}
///////////////////////////////////////////////////////////////////////
//Variants of the Floodfill Algorithm
///////////////////////////////////////////////////////////////////////
126
Grafika Komputer Pertemuan Ke-10
//Recursive 4way floodfill, crashes if recursion stack is full
void floodFill4(int x, int y, Uint32 newColor, Uint32 oldColor)
{
if(x >= 0 && x < w && y >= 0 && y < h && screenBuffer[x][y] ==
oldColor && screenBuffer[x][y] != newColor)
{
screenBuffer[x][y] = newColor; //set color before starting
recursion!
floodFill4(x + 1, y,
newColor, oldColor);
floodFill4(x 1, y,
newColor, oldColor);
floodFill4(x,
y + 1, newColor, oldColor);
floodFill4(x,
y 1, newColor, oldColor);
}
}
//Recursive 8way floodfill, crashes if recursion stack is full
void floodFill8(int x, int y, Uint32 newColor, Uint32 oldColor)
{
if(x >= 0 && x < w && y >= 0 && y < h && screenBuffer[x][y] ==
oldColor && screenBuffer[x][y] != newColor)
{
screenBuffer[x][y] = newColor; //set color before starting
recursion!
floodFill8(x +
floodFill8(x
floodFill8(x,
floodFill8(x,
floodFill8(x +
floodFill8(x
floodFill8(x
floodFill8(x +
1, y,
newColor, oldColor);
1, y,
newColor, oldColor);
y + 1, newColor, oldColor);
y 1, newColor, oldColor);
1, y + 1, newColor, oldColor);
1, y 1, newColor, oldColor);
1, y + 1, newColor, oldColor);
1, y 1, newColor, oldColor);
}
}
//4way floodfill using our own stack routines
void floodFill4Stack(int x, int y, Uint32 newColor, Uint32 oldColor)
{
if(newColor == oldColor) return; //avoid infinite loop
emptyStack();
if(!push(x, y)) return;
while(pop(x, y))
{
screenBuffer[x][y] = newColor;
if(x + 1 < w && screenBuffer[x + 1][y] == oldColor)
{
if(!push(x + 1, y)) return;
}
if(x 1 >= 0 && screenBuffer[x 1][y] == oldColor)
{
if(!push(x 1, y)) return;
}
if(y + 1 < h && screenBuffer[x][y + 1] == oldColor)
{
127
Grafika Komputer Pertemuan Ke-10
if(!push(x, y + 1)) return;
}
if(y 1 >= 0 && screenBuffer[x][y 1] == oldColor)
{
if(!push(x, y 1)) return;
}
}
}
//8way floodfill using our own stack routines
void floodFill8Stack(int x, int y, Uint32 newColor, Uint32 oldColor)
{
if(newColor == oldColor) return; //if you don't do this: infinite
loop!
emptyStack();
if(!push(x, y)) return;
while(pop(x, y))
{
screenBuffer[x][y] = newColor;
if(x + 1 < w && screenBuffer[x + 1][y] == oldColor)
{
if(!push(x + 1, y)) return;
}
if(x 1 >= 0 && screenBuffer[x 1][y] == oldColor)
{
if(!push(x 1, y)) return;
}
if(y + 1 < h && screenBuffer[x][y + 1] == oldColor)
{
if(!push(x, y + 1)) return;
}
if(y 1 >= 0 && screenBuffer[x][y 1] == oldColor)
{
if(!push(x, y 1)) return;
}
if(x + 1 < w && y + 1 < h && screenBuffer[x + 1][y + 1] ==
oldColor)
{
if(!push(x + 1, y + 1)) return;
}
if(x + 1 < w && y 1 >= 0 && screenBuffer[x + 1][y 1] ==
oldColor)
{
if(!push(x + 1, y 1)) return;
}
if(x 1 > 0 && y + 1 < h && screenBuffer[x 1][y + 1] ==
oldColor)
{
if(!push(x 1, y + 1)) return;
}
128
Grafika Komputer Pertemuan Ke-10
}
//stack friendly and fast floodfill algorithm
void floodFillScanline(int x, int y, Uint32 newColor, Uint32 oldColor)
{
if(oldColor == newColor) return;
if(screenBuffer[x][y] != oldColor) return;
int y1;
//draw current scanline from start position to the top
y1 = y;
while(screenBuffer[x][y1] == oldColor && y1 < h)
{
screenBuffer[x][y1] = newColor;
y1++;
}
//draw current scanline from start position to the bottom
y1 = y 1;
while(screenBuffer[x][y1] == oldColor && y1 >= 0)
{
screenBuffer[x][y1] = newColor;
y1;
}
//test for new scanlines to the left
y1 = y;
while(screenBuffer[x][y1] == newColor && y1 < h)
{
if(x > 0 && screenBuffer[x 1][y1] == oldColor)
{
floodFillScanline(x 1, y1, newColor, oldColor);
}
y1++;
}
y1 = y 1;
while(screenBuffer[x][y1] == newColor && y1 >= 0)
{
if(x > 0 && screenBuffer[x 1][y1] == oldColor)
{
floodFillScanline(x 1, y1, newColor, oldColor);
}
y1;
}
//test for new scanlines to the right
y1 = y;
while(screenBuffer[x][y1] == newColor && y1 < h)
{
if(x < w 1 && screenBuffer[x + 1][y1] == oldColor)
{
129
Grafika Komputer Pertemuan Ke-10
while(screenBuffer[x][y1] == newColor && y1 >= 0)
{
if(x < w 1 && screenBuffer[x + 1][y1] == oldColor)
{
floodFillScanline(x + 1, y1, newColor, oldColor);
}
y1;
}
}
//The scanline floodfill algorithm using our own stack routines, faster
void floodFillScanlineStack(int x, int y, Uint32 newColor, Uint32
oldColor)
{
if(oldColor == newColor) return;
emptyStack();
int y1; //note: if you use y here, we're working vertically. This
goes much faster in this case, because reading and writing the
buffer[x][y] goes faster if y is incremented/decremented
bool spanLeft, spanRight;
if(!push(x, y)) return;
while(pop(x, y))
{
y1 = y;
while(screenBuffer[x][y1] == oldColor && y1 >= 0) y1;
y1++;
spanLeft = spanRight = 0;
while(screenBuffer[x][y1] == oldColor && y1 < h)
{
screenBuffer[x][y1] = newColor;
if(!spanLeft && x > 0 && screenBuffer[x 1][y1] ==
oldColor)
{
if(!push(x 1, y1)) return;
spanLeft = 1;
}
else if(spanLeft && x > 0 && screenBuffer[x 1][y1] !=
oldColor)
{
spanLeft = 0;
}
if(!spanRight && x < w 1 && screenBuffer[x + 1][y1] ==
oldColor)
{
if(!push(x + 1, y1)) return;
spanRight = 1;
}
else if(spanRight && x < w 1 && screenBuffer[x + 1][y1]
!= oldColor)
{
spanRight = 0;
}
y1++;
}
130
Grafika Komputer Pertemuan Ke-10
}
}
///////////////////////////////////////////////////////////////////////
//Auxiliary Functions
///////////////////////////////////////////////////////////////////////
void clearScreenBuffer(ColorRGB color)
{
for(int x = 0; x < w; x++)
for(int y = 0; y < h; y++)
{
screenBuffer[x][y] = RGBtoINT(color);
}
}
bool paint_drawLine(int x1, int y1, int x2, int y2, ColorRGB color)
{
if(x1 < 0 || x1 > w 1 || x2 < 0 || x2 > w 1 || y1 < 0 ||
y1 > h
1 || y2 < 0 || y2 > h 1) return 0;
int deltax = abs(x2 x1); // The difference between the x's
int deltay = abs(y2 y1); // The difference between the y's
int x = x1; // Start x off at the first pixel
int y = y1; // Start y off at the first pixel
int xinc1, xinc2, yinc1, yinc2, den, num, numadd, numpixels,
curpixel;
if (x2 >= x1) // The xvalues are increasing
{
xinc1 = 1;
xinc2 = 1;
}
else // The xvalues are decreasing
{
xinc1 = 1;
xinc2 = 1;
}
if (y2 >= y1) // The yvalues are increasing
{
yinc1 = 1;
yinc2 = 1;
}
else // The yvalues are decreasing
{
yinc1 = 1;
yinc2 = 1;
}
if (deltax >= deltay) // There is at least one xvalue for every y
value
{
xinc1 = 0; // Don't change the x when numerator >= denominator
yinc2 = 0; // Don't change the y for every iteration
den = deltax;
num = deltax / 2;
numadd = deltay;
numpixels = deltax; // There are more xvalues than yvalues
}
131
Grafika Komputer Pertemuan Ke-10
else // There is at least one yvalue for every xvalue
{
xinc2 = 0; // Don't change the x for every iteration
yinc1 = 0; // Don't change the y when numerator >= denominator
den = deltay;
num = deltay / 2;
numadd = deltax;
numpixels = deltay; // There are more yvalues than xvalues
}
for (curpixel = 0; curpixel <= numpixels; curpixel++)
{
screenBuffer[x % w][y % h] = RGBtoINT(color); // Draw the
current pixel
num += numadd; // Increase the numerator by the top of the
fraction
if (num >= den) // Check if numerator >= denominator
{
num = den; // Calculate the new numerator value
x += xinc1; // Change the x as appropriate
y += yinc1; // Change the y as appropriate
}
x += xinc2; // Change the x as appropriate
y += yinc2; // Change the y as appropriate
}
return 1;
}
132