setRGB(x,y,color)-Frage


#1
Hallo,

ich habe kein Problem mit dieser Methode und weiß wie man sie verwendet, aber ich habe einen kleinen rekursiven Füllalgorithmus für beliebige Grafikprimitiven implementiert und dieser expandiert Pixel in vier Richtungen. Wenn man z.B. einen Kreis füllen möchte und den Mittelpunkt als Startpunkt angibt sollte meine Füllmethode den Kreis rekursiv Füllen. Geht aber nicht. Das ganze geht nur, wenn man in nur 3 Richtungen expandiert und einen Startpixel ganz am Rand des Kreises angibt.

Liegt das an setRGB(x,y,color) oder an getPixel(int x,int y)?????

Hier meine Methoden:

Java:
public boolean rangeOK(int x,int y){
        if((x >= 0 && x < image.getWidth())&&(y >= 0 && y < image.getHeight()))return true;
        return false;
    }
   
    public boolean getPixel(int x,int y){
        if(image.getRGB(x,y)!=color)return true; ... bringt er hier einen Stackoverflowfehler
        return false;
    }
   
    public void boundaryFill(int x,int y){
        if(rangeOK(x,y)&&getPixel(x,y)){
            setPixel(x,y);
            boundaryFill(x-1,y);
            boundaryFill(x,y+1);
            boundaryFill(x+1,y);
            //boundaryFill(x,y-1); Wenn das an ist....
        }
    }

public void setPixel(int x,int y){
        image.setRGB(x,y,color);
    }
Der Aufruf von boundaryFill erfolgt in der Zeichenmethode mittels repaint.
 
#3
Ich möchte dir ja nicht zu Nahe treten aber das ganze ist ganz einfach nachvollziehbar und das nicht nur für mich. Ich hab ein JFrame darauf ein JPanel und darauf ein BufferedImage auf dem ich Pixel anknipse oder eben nicht. Dein Link bringt mir fast nix sorry. Hab mich nochmal schlau gemacht über stackoverflow (wiki) ,aber mir ist noch nicht ganz klar wieso der entsteht. Meiner Meinung nach müsste das entweder mit der funktionsweise von setRGB(x,y,color) zu tun haben oder die Rekursion ist wie du schon sagst mangelhaft.

Übrigens der Kreis wird mittels Bresenham Algorithmus gezeichnet. Die Methode, die ich hier nicht geposted habe ermittelt die anzuknipsenden Pixel zur Beschreibung eines Kreises. Aber mit dem Füllen hat das eig. nichts zu tun, zumal man den Kreis auch mit drawOval bzw fillOval zeichnen könnte, aber das nur am Rande.

Versteh mich bidde nicht falsch ich möchte dich damit nicht angreifen oder so, im Prinzip bin ich sowieso dankbar wenn mir überhaupt jemand antwortet.
 

Bratkartoffel

gebratene Kartoffel
Premium-User
#5
Hi,

was ich damit meinte, ist dass ich nicht einfach dienen Code in mein IntelliJ reinkopieren, starten und debuggen kann. Sprich, ich muss selbst Code aussen rum schreiben und es ist nicht auf den ersten Blick ersichtlich, was du sonst noch alles so machst. (Welchen Datentyp hat "image"? Wo ist überhaupt deine Rekursion? Wie sieht deine Abbruchbedingung aus? etc)

Mein Link zeigt zu einer Frage auf SO ("JVM option -Xss - What does it do exactly?"), welche dir weitere Infos dazu liefert, wie du die Stacksize der JVM anpassen kannst und was das bewirkt. Einfacher gesagt vermute ich, dass du die -Xss setzen solltest; Wenn das dann funktioniert, dann ist deine Rekursion schlichtweg zu "tief". Jeder Thread hat einen Stack. Mit jedem Funktionsaufruf wird ein neuer Stackeintrag erstellt, mit jedem return wird dieser wieder entfernt (mehr Details). Mit jedem Rekursionsdurchlauf wird also ein neuer Eintrag auf dem Stack erstellt und dieser läuft irgendwann über (und die Exception kommt).

Grüsse,
BK
 

Bratkartoffel

gebratene Kartoffel
Premium-User
#7
Hi,

das gibst du der JVM beim Start mit:
Code:
java -Xss1m MeineKlasse.class
java -Xss1m -jar MeineApp.jar
Wenn du es aus der IDE startest, dann musst das dort angeben.

Aber falls du nicht unbedingt Rekursion verwenden musst, dann nimm sie hier raus und löse das ganze Iterativ.

Grüsse,
BK
 
#8
Ha ich denke ich weiß jetzt was du mit "zu tief" meinst, zu viele rekursive Aufrufe. Und genau daran liegts. Wenn man den Stack hoch setzt geht's. Ist aber nicht sehr effizient denke ich. Ich weiß allerdings nicht wie ich das mit nur einem rekursiven Aufruf lösen könnte?
 

Bratkartoffel

gebratene Kartoffel
Premium-User
#9
Hi,

wenn du nur die Fläche befüllen willst, dann kannst du es auch mit 2 Schleifen machen:
Java:
    public void boundaryFill() {
        for(int x = 0; x < image.getWidth(); x++) {
            for(int y = 0; y < image.getHeight(); y++) {
                setPixel(x, y);
            }
        }
    }
Deine anderen Methoden lassen sich übrigens in der Grundversion auch etwas vereinfachen:
Java:
    public boolean rangeOK(int x, int y) {
        return (x >= 0 && x < image.getWidth()) && (y >= 0 && y < image.getHeight());
    }

    public boolean getPixel(int x, int y) {
        return image.getRGB(x, y) != color;
    }
Grüsse,
BK