Thema: Delphi FloodFill Rekursiv

Einzelnen Beitrag anzeigen

Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#17

Re: FloodFill Rekursiv

  Alt 21. Jun 2007, 01:10
Zuerst ein paar Anmerkungen zum Code, wo Dinge auftauchen, die ich für umständlich bzw. komisch gelöst halte:

1) In diesem Fall würde ich eine Nested-Function verwenden, um u.a. das mehrmalige Übergeben der Map zu umgehen. Das verhindert auch, dass die Map von aussen mitgegeben werden muss, was ja garkeinen Sinn ergibt, da sie rein interne Angelegenheit des Floodfills ist. Strukturell in etwa so:
Delphi-Quellcode:
procedure FloodFill(ABmp: TBitmap; x, y: Integer; AColor: TColor; Border: TColor);
var
  Map: TBoolmap;
  ix, iy: Integer;

  procedure DoPixel(ax, ay: Integer);
  begin
    if ({ax und ay im gültigen Bereich}) and not Map[ax, ay] then
    begin
      ABmp.Canvas.Pixels[ax, ay] := Zielfarbe;
      Map[ax, ay] := true;
      DoPixel(ax+1, ay );
      DoPixel(ax , ay+1);
      DoPixel(ax-1, ay );
      DoPixel(ax , ay-1);
    end;
  end;

begin
  // Bei SetLength gehen so viele Argumente wie dein Array Dimensionen hat ;)
  // Zudem ist es so "richtig herum", erst x dann y Koordinate. Bei dir ists vertauscht
  // und damit anders herum als bei Pixels. Unschön und fehlerträchtig.
  SetLength(Map, ABmp.Width, ABmp.Height);

  // Map initialisieren, und dabei gleich die Border abtragen. Erspart die zusätzliche
  // Abfrage auf diese für jedes Pixel nachher.
  for iy := 0 to ABmp.Heigt-1 do
    for ix := 0 to ABmp.Width-1 do
      if ABmp.Canvas.Pixels[ix, iy] = Border then
        Map[ix, iy] := true
      else
        Map[ix, iy] := false;

  // Eigentichen Fill starten
  DoPixel(x, y);
end;
So in etwa würd ich das vermutlich machen =)


2)(x <= ABmp.Width-1) and (y <= ABmp.Height-1) Naja, ich hab zwar geschrieben, dass es bis Width/Height-1 geht, aber performanter und lesbarer wäre es gewesen statt obigem folgendes zu machen:
(x < ABmp.Width) and (y < ABmp.Height) Selber Effekt, ohne noch zusätzliche Arithmetik. Und wenn ich nicht irre, ist ein Vergleich auf echt kleiner oder größer sogar noch ne Picosekunde schneller als auf kleiner/größer-gleich


3) Dein Stack overflow ist im übrigen interessant! Ich hätte eher eine Bereichsverletzung, oder mindestens ne AV erwartet. Bei:
Delphi-Quellcode:
  if Map[y,x] then
    exit;
Greifst du auf Elemente zu, die evtl. garnicht mehr im Bereich sind. Ob x und y zwischen 0 und Width/Height sind, prüfst du erst später.



Gruss,
Fabian
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat