【问题标题】:Flood fill algorithm for bucket tool in P5.js electron paint applicationP5.js电子油漆应用中桶工具的填充算法
【发布时间】:2018-06-30 13:25:18
【问题描述】:

我正在尝试为我用电子.js 和 P5.js 制作的画布应用程序创建一个桶工具。每当用户点击画布并且他的mode 变量等于“fill”时,它就会调用floodFill 函数。我试图从这里实现算法:https://en.wikipedia.org/wiki/Flood_fill#Pseudocode(基于堆栈的递归实现(四向)),但我有一个问题 - 我正在达到最大调用堆栈。 我将所有内容渲染到屏幕上的方式是我有一个名为drawing 的数组,并且您可以绘制的事物类型(圆形,方形)有构造函数,所以我创建了一个像素构造函数,以便我可以每次都渲染它,我无法调用updatePixels(),因为我使用draw() 函数渲染每一帧的所有内容。 这是我的 floodFill 函数:

function floodFill(x, y, target_col, replace_col) {
   if (x >= 0 && y >= 0 && x <= width && y <= height) {
        let index = (x + y * width) * 4;
        if (target_col === replace_col) {
            return;
        } else if (
            pixels[index] !== target_col.levels[0] &&
            pixels[index + 1] !== target_col.levels[1] &&
            pixels[index + 2] !== target_col.levels[2] &&
            pixels[index + 3] !== target_col.levels[3]
        ) {
            return;
        } else {
            drawing.push(new Pixel(x, y, replace_col));
            floodFill(x, y - 1, target_col, replace_col);
            floodFill(x, y + 1, target_col, replace_col);
            floodFill(x - 1, y, target_col, replace_col);
            floodFill(x + 1, y, target_col, replace_col);
        }
    }
}

这就是我调用函数的方式:

if (mode === "fill") {
    loadPixels();
    let index = (mouseX + mouseY * width) * 4;

    // target_color = what the user wants to replace
    let target_color = color(
        pixels[index],
        pixels[index + 1],
        pixels[index + 2],
        pixels[index + 3]
    );
   // replacement_color = the color that will be instead of the target_color
   let replacement_color = color(current_color);
    floodFill(mouseX, mouseY, target_color, replacement_color);
}

顺便说一句,在else if 中的floodFill 函数中,我使用了这种技术,因为简单地执行color(pixels[index], pixels[index + 1], pixels[index + 2], pixels[index + 3]) !== target_col 不起作用

编辑: 我意识到我的 floodFill 函数有一个错误,我的 else if 几乎永远不会是真的,因为它还会尝试检查 alpha 是否不相等并且它们几乎总是 255。所以我添加到 else if 这个:

else if (
     (pixels[index] !== target_col.levels[0] &&
         pixels[index + 1] !== target_col.levels[1] &&
        pixels[index + 2] !== target_col.levels[2]) ||
    pixels[index + 3] !== target_col.levels[3]
 ) {

现在发生的情况是,如果我尝试填充一些东西,它会画一条直线直到它达到另一种颜色,然后达到最大堆栈大小, 例子: 这可能是因为在floodFill 函数中,我进行的第一个递归调用是对y - 1(向上)。 我很想听听更多的建议

另一个编辑: 我发现在递归部分的floodFill 中,我用y - 1 调用它,然后用y + 1 调用它,这是没有意义的,因为它上升然后下降意味着它保持在同一个像素,所以我将它编辑为像这样:

floodFill(x, y - 1, target_col, replace_col);
floodFill(x - 1, y, target_col, replace_col);
floodFill(x, y + 1, target_col, replace_col);
floodFill(x + 1, y, target_col, replace_col);

现在它显示如下:

【问题讨论】:

    标签: javascript p5.js flood-fill


    【解决方案1】:

    这是 p5.js 中的一个填充示例。

    在 cavas 中绘制一个封闭的形状,然后在其中按住 shift 单击。

    var stack = [];
    var oldColor;
    var fillColor
    
    
    function setup() {
      createCanvas(windowWidth, windowHeight);
      noSmooth();
      fillColor = color(0, 255, 0);
    }
    
    function windowResized() {
      resizeCanvas(windowWidth, windowHeight);
    }
    
    function draw() {
    
      function matches(c, x, y) {
        return JSON.stringify(get(x, y)) === JSON.stringify(c);
      }
    
      if (!stack.length) return;
    
      let p = stack.pop();
      let x1 = p.x, y = p.y;
      while (x1 > 0 && matches(oldColor, x1 - 1, y))
        x1--;
    
      let spanAbove = false, spanBelow = false;
    
      for (let x2 = x1 + 1; x2 < width && matches(oldColor, x2, y); ++x2) {
        set(x2, y, fillColor);
    
        if (y > 0 && spanAbove !== matches(oldColor, x2, y - 1)) {
          if (!spanAbove)
            stack.push({ x: x2, y: y - 1 });
          spanAbove = !spanAbove;
        }
        if (y < height - 1 && spanBelow !== matches(oldColor, x2, y + 1)) {
          if (!spanBelow)
            stack.push({ x: x2, y: y + 1 });
          spanBelow = !spanBelow;
        }
      }
    
      updatePixels();
    }
    
    function mouseDragged() {
      if (keyIsDown(SHIFT)) return;
      stroke(255);
      strokeWeight(2);
      line(pmouseX, pmouseY, mouseX, mouseY);
    }
    
    function mouseClicked() {
      if (keyIsDown(SHIFT)) {
        oldColor = get(mouseX, mouseY);
        loadPixels();
        stack = [];
        stack.push({ x: mouseX, y: mouseY });
      }
    }
    html,
    body {
      margin: 0;
      padding: 0;
      border: none;
      background: black;
    }
    
    canvas {
      display: block;
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"&gt;&lt;/script&gt;

    【讨论】:

      猜你喜欢
      • 2020-12-27
      • 1970-01-01
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-01
      • 2016-01-13
      • 1970-01-01
      相关资源
      最近更新 更多