Universelle Füllverfahren stützen sich auf die Nachbarschaft eines Pixels. Abbildung 4.1 zeigt zwei Varianten.
|
|
Obacht:
Gebiete, die nur durch 8-way-stepping erreicht werden können, werden beim Füllen mit 4-way-stepping ``vergessen'', wird hingegen die Nachbarschaft über 8-way-stepping definiert, so ``läuft die Farbe aus''.
Bild 4.1 zeigt beide Effekte.
|
|
boolean get_pixel ( // liefert true, wenn Pixel p Point p) // die Vordergrundfarbe hat
und
boolean range_ok ( // liefert false, wenn Pixel p
Point p) // ausserhalb des Bildbereichs
Der Nachteil der sehr ineffizienten Methode boundary_fill liegt darin, daß für jedes Pixel innerhalb der Begrenzungskurve(n) (mit Ausnahme der Randpixel des inneren Gebiets) der Algorithmus viermal aufgerufen wird. Dadurch werden die Pixel mehrfach auf dem Stapel abgelegt.
Eine Beschleunigung des Verfahrens läßt sich dadurch erreichen, daß auf dem Stapel jeweils Repräsentanten für noch zu füllende Zeilen abgelegt werden, d.h. nach dem Einfärben einer kompletten horizontalen Linie werden von den unmittelbar angrenzenden Zeilen solche Punkte auf den Stapel gelegt, die noch nicht gefüllt worden sind und die unmittelbar links von einer Begrenzung liegen.
/*************************************************************************************/ /* */ /* Fuellen einer durch Vordergrundfarbe umrandeten Flaeche */ /* */ /*************************************************************************************/ private void boundary_fill( // setzt alle Nicht-Vordergrund-Pixel Point p) // beginnend bei Position p auf Vordergrund { if ( range_ok(p) && !get_pixel(p) ) { // falls p keine Vordergrundfarbe hat set_pixel(p); // setze Vordergrundfarbe boundary_fill( new Point(p.x+1, p.y )); // 4-way stepping boundary_fill( new Point(p.x, p.y+1 )); boundary_fill( new Point(p.x-1, p.y )); boundary_fill( new Point(p.x, p.y-1 )); } } /*************************************************************************************/ /* */ /* Leeren einer durch Vordergrundfarbe definierten Flaeche */ /* */ /*************************************************************************************/ private void boundary_empty( // setzt alle Vordergrund-Pixel beginnend Point p) // bei Position p auf Hintergrundfarbe { if ( range_ok(p) && get_pixel(p) ) { // falls p Vordergrundfarbe hat del_pixel(p); // setze Hintergrundfarbe boundary_empty( new Point( p.x+1, p.y )); // 8-way-stepping boundary_empty( new Point( p.x+1, p.y+1 )); boundary_empty( new Point( p.x, p.y+1 )); boundary_empty( new Point( p.x-1, p.y+1 )); boundary_empty( new Point( p.x-1, p.y )); boundary_empty( new Point( p.x-1, p.y-1 )); boundary_empty( new Point( p.x, p.y-1 )); boundary_empty( new Point( p.x+1, p.y-1 )); } } |
/*****************************************************************************/ /* */ /* linienweises Fuellen einer durch Vordergrundfarbe umrandeten Flaeche */ /* */ /*****************************************************************************/ private void fillRowByRow(int x, int y, Graphics g) { int lg; // nicht gesetzte Pixel ganz int rg; // links/rechts in dieser Z. Punkt hilf; // Hilfpunkt int px = x; // lokale Kopie while(!isPixelSet(x, y)) { // Solange Pixel ungesetzt setPixelInBuf(x, y); // Pixel merken und setzen hilf = new Punkt(x, y); hilf.paint(g); x--; // naechstes Pixel links } lg = x+1; // 1 zu weit gelaufen x = px + 1; // da (px,y) schon gesetzt while(!isPixelSet(x, y)) { // Solange Pixel ungesetzt setPixelInBuf(x, y); // Pixel merken und setzen hilf = new Punkt(x, y); hilf.paint(g); x++; // naechstes Pixel rechts } rg = x-1; // 1 zu weit gelaufen for(int pos = rg; pos >= lg; pos--) { // von rechts nach links if(!isPixelSet(pos, y - 1)) { // falls Pixel in Reihe ueber // dieser nicht gesetzt: fillRowByRow(pos,y-1, g); // Repraesentant! neuer Aufruf } if(!isPixelSet(pos, y + 1)) { // falls Pixel in Reihe unter // dieser nicht gesetzt: fillRowByRow(pos,y+1, g); // Repraesentant! neuer Aufruf } } return; } |