2010-02-23 6 views
0

J'essaye d'écrire ma propre fonction de remplissage en ActionScript3, car celle fournie par Adobe n'est pas assez flexible (vous ne pouvez donner qu'une couleur cible, je voudrais donner une gamme de couleurs cibles .)Floodfill dans ActionScript 3

Ainsi, le terrible code je suis venu avec à ce jour est la suivante:

private function beginAlgortime(xx:int,yy:int):void 
{ 
    if (bmp.bitmapData.getPixel(xx, yy) != 0x333333) { 

     bmp.bitmapData.setPixel(xx, yy, 0x333333); 

     beginAlgortime(xx + 1, yy); 
     beginAlgortime(xx + 1, yy+1); 
     beginAlgortime(xx + 1, yy - 1); 

     beginAlgortime(xx , yy+1); 
     beginAlgortime(xx , yy - 1); 

     beginAlgortime(xx - 1, yy); 
     beginAlgortime(xx - 1, yy+1); 
     beginAlgortime(xx - 1, yy-1); 
    } 
} 

une fonction récursive assez basique .. Mais en utilisant évidemment cette méthode, un lecteur flash chie sur moi :) Quelqu'un at-il une solution pour cela? Bravo!

+0

parler de temps, je tentais la même chose aujourd'hui exacte. Malheureusement, je ne pouvais pas secouer les erreurs de stackoverflow de trop d'appels récursifs. – Allan

Répondre

2

Il n'est pas nécessaire de revenir directement aux diagonales, car la récursion verticale et horizontale touchera quand même ces pixels.

que voulez-vous dire par «remplissage»? et qu'entendez-vous par "gamme de couleurs"? La routine que vous avez fournie remplira la totalité du bitmap avec 0x333333

et il ne se terminera pas, puisque vous ne vérifiez jamais si vous laissez les limites de bitmaps.

+1

oui. @Jaaq Jetez un coup d'oeil sur les algorithmes ici http://www.cs.nps.navy.mil/people/faculty/capps/iap/class1/fill/fill.html Le remplissage des limites se traduira par un stackoverflow (environ 3/4 de remplir une image avant qu'il ne se produise) – Allan

+0

J'ai trouvé une bonne solution pour floodFilling: http://www.multimediacollege.be/2010/04/optimizing-the-floodfill-method/ – Jaaq

0

Vous pouvez essayer de le convertir d'une fonction récursive en une fonction itérative qui utilise un tableau au lieu de la pile de programmes.

est ici une implémentation itérative de FloodFill tel que décrit dans the article Allan mentioned:

function floodFill(bmpData:BitmapData, startX:int, startY:int, fill:uint, old:uint):void 
{ 
    var queue:Array = new Array(); 

    queue.push(new Point(startX, startY)); 

    var iterations:uint = 0; 
    var bmpWidth:int = bmpData.width; 
    var bmpHeight:int = bmpData.height; 

    var searchBmp:BitmapData = new BitmapData(bmpData.width, bmpData.height); 
    var currPoint:Point, newPoint:Point; 
    while (queue.length > 0) 
    { 
     currPoint = queue.shift(); 
     ++iterations; 

     if (currPoint.x < 0 || currPoint.x >= bmpWidth) continue; 
     if (currPoint.y < 0 || currPoint.y >= bmpHeight) continue; 

     searchBmp.setPixel(currPoint.x, currPoint.y, 0x00); 

     if (bmpData.getPixel(currPoint.x, currPoint.y) == old) 
     { 
      bmpData.setPixel(currPoint.x, currPoint.y, fill); 

      if (searchBmp.getPixel(currPoint.x + 1, currPoint.y) == 0xFFFFFF) 
      { 
       queue.push(new Point(currPoint.x + 1, currPoint.y)); 
      } 
      if (searchBmp.getPixel(currPoint.x, currPoint.y + 1) == 0xFFFFFF) 
      { 
       queue.push(new Point(currPoint.x, currPoint.y + 1)); 
      } 
      if (searchBmp.getPixel(currPoint.x - 1, currPoint.y) == 0xFFFFFF) 
      { 
       queue.push(new Point(currPoint.x - 1, currPoint.y)); 
      } 
      if (searchBmp.getPixel(currPoint.x, currPoint.y - 1) == 0xFFFFFF) 
      { 
       queue.push(new Point(currPoint.x, currPoint.y - 1)); 
      } 
     } 

    }  
    trace("iterations: " + iterations); 
} 

Edit: Après avoir essayé plusieurs façons de garder une trace des pixels ont déjà été fouillés, je me suis aperçu que l'utilisation d'un second BitmapData instance fonctionne vraiment bien. J'ai mis à jour le code en conséquence.

Ce code remplit un bitmap 2000 x 1400 en ~ 14 secondes sur mon ordinateur. Pour une meilleure expérience utilisateur, vous devez interrompre le traitement de remplissage sur plusieurs cadres, afin que l'utilisateur n'ait pas à regarder une icône en attente. Oh, et cela n'affecte qu'une seule couleur, mais il devrait être facile de le modifier pour prendre plusieurs couleurs, ou un seuil de couleur, ou similaire.

Modifier pour ajouter: L'article Flood fill sur Wikipedia contient plusieurs suggestions d'algorithmes.

0

C'est ce que je l'ai utilisé:

 

private function floodFill(bitmapData: BitmapData, x: int, y: int, backColor: uint, fillColor: uint): void 
{ 
    var data: Vector. = bitmapData.getVector(bitmapData.rect); 

    var queueX:Vector. = new Vector.(); 
    var queueY:Vector. = new Vector.(); 

    queueX.push(x); 
    queueY.push(y); 

    while (queueX.length > 0) { 
     x = queueX.shift(); 
     y = queueY.shift(); 

     if (x = width || y = height) 
      return; 

     if (data[y*width + x] == backColor) { 
      data[y*width + x] = fillColor; 

      queueX.push(x+1); 
      queueY.push(y); 

      queueX.push(x-1); 
      queueY.push(y); 

      queueX.push(x); 
      queueY.push(y+1); 

      queueX.push(x); 
      queueY.push(y-1); 
     } 
    } 

    bitmapData.setVector(bitmapData.rect, data); 
}