"铲斗填充”;Javascript或coffeescript中的算法

"Bucket Fill" algorithm in Javascript or coffeescript

本文关键字:coffeescript 算法 Javascript quot 填充      更新时间:2023-09-26

我正在写一个小的coffeescript/js应用程序,它允许用户设计图标(16x16像素或32X32像素)。图标实际上是一个带有颜色单元格的二维数组。单元格可以有颜色,也可以为空。

我希望用户能够用"桶式绘制"工具填充空白单元格。

这意味着

  • 如果用户单击一个空白单元格,则单击的单元格旁边的所有空白单元格都将填充所选的颜色,直到达到彩色单元格

  • 如果用户单击彩色单元格,则会填充单击单元格旁边的所有共享相同颜色的单元格,但不会填充空白单元格或彩色单元格(使用其他颜色)。

该应用程序已经允许用户用选定的颜色逐个填充单元格,或者用钢笔工具删除彩色单元格。

有什么建议吗?

(ps:我不使用html画布绘制)

由于这只是16x16或32x32,因此可以使用递归解决方案:

假设您的起点是将像素x/y从颜色A更改为颜色B(A或B可以为空)。

在伪代码中:

function floodfill(x,y,A,B) {
  if ((x<0) || (x>15) || (y<0) || (y>15)) return;
  if (get_color(x,y)!=A) return;
  set_color(x,y,B);
  floodfill(x-1,y-1,A,B);
  floodfill(x-1,y,A,B);
  floodfill(x-1,y+1,A,B);
  floodfill(x,y-1,A,B);
  floodfill(x,y+1,A,B);
  floodfill(x+1,y-1,A,B);
  floodfill(x+1,y,A,B);
  floodfill(x+1,y+1,A,B);
}

我不完全确定你在寻找什么类型的建议,但你应该看看洪泛填充算法。

它在维基百科上:http://en.wikipedia.org/wiki/Flood_fill

好吧,下面是我在coffeescript中解决问题的方法。这是一个使用画布的例子。脚本应该在任何有一个id为canvas的canvas元素的页面上运行,因为stackerflow问题,我不得不创建自己的堆栈。

log = ->
  console.log arguments
class Point
  constructor:(@x,@y)->
class BucketFiller
  MAXITERATION:100000
  factor:1
  fill : (ctx,pixel, colCible, colRep)->
    P = []
    max = @MAXITERATION
    if @getColorAtPixel(ctx,pixel)!=colCible then return null
    P.push(pixel)
    while  P.length > 0 and max >=0
      --max
      currentpixel = P.pop()
      @fillRect(ctx,currentpixel.x,currentpixel.y,@factor,@factor,colRep)
      if @isInCanvas(ctx,currentpixel)
        if @getColorAtPixel(ctx,@up(currentpixel)) == colCible then P.push(@up(currentpixel))
        if @getColorAtPixel(ctx,@down(currentpixel)) == colCible then P.push(@down(currentpixel))
        if @getColorAtPixel(ctx,@right(currentpixel)) == colCible then P.push(@right(currentpixel))
        if @getColorAtPixel(ctx,@left(currentpixel)) == colCible then P.push(@left(currentpixel))
    return
  fillRect:(ctx,x,y,width,height,color)->
    ctx.fillStyle = color
    ctx.fillRect(x,y,width,height)
    return
  down :(pixel)->
    return {x:pixel.x,y:pixel.y-@factor}
  up:(pixel)->
    return {x:pixel.x,y:pixel.y+@factor}
  right :(pixel)->
    return {x:pixel.x+@factor,y:pixel.y}
  left :(pixel)->
    return {x:pixel.x-@factor,y:pixel.y}
  getColorAtPixel:(ctx,pixel)->
    try
      imageData = ctx.getImageData(pixel.x,pixel.y,1,1)
    catch e
      return null
    return @rgbArrayToCssColorString(imageData.data)
  rgbArrayToCssColorString:(array)->
    result = "rgb(#{array[0]},#{array[1]},#{array[2]})"
    return result
  isInCanvas : (ctx,pixel)->
    result = ((0 <= pixel.x <= ctx.canvas.width) and (0 <= pixel.y <= ctx.canvas.height))
    return result
main=->
    buckfiller = new BucketFiller()
    log("start")
    canvas  = document.getElementById("canvas")
    ctx = canvas.getContext("2d")
    penPosition = new Point(2,10)
    fillColor = "rgb(255,0,0)"
    colCible = buckfiller.getColorAtPixel(ctx,penPosition)
    try
      buckfiller.fill(ctx,penPosition,colCible,fillColor)
    catch e
      log e
window.onload=->
  main()