Huhu!
Als ich eben gelesen habe, das jemand eine Floodfill funktion gesucht hat, konnte ichs mir nicht nehmen lassen, eine zu basteln.
Da ich das ganze aber in Blitzmax umgesetzt habe und auch nicht auf Rekursion gesetzt habe, wollte ich das nicht umbedingt als lösung posten: TList umzusetzen ist zb ne ecke schwerer als ne simple, gute überwachte Rekursion in BB.
Anyways.
funktionsweise:
Breitensuche. Ganz Simpel. ein startpunkt XY wird in eine liste geschmissen, ein array um bereits geprüftes zu überwachen wird angelegt und los gehts: Solange punkte da sind, umkreis checken.
Das ganze hat eine Schwellwert funktion: Man gibt eine Schwelle im bereich von 0 bis 255 an, wie die einzelnen Komponenten sich voneinander unterscheiden können.
Das ganze ist noch mit recht dreckigem testprogramm ausgestattet..
Hier der code. Funktionen stehen unten an, einfach nach PIX_ suchen.
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN]
SuperStrict
Graphics(1024, 768)
Global background:TPixmap = CreatePixmap(GraphicsWidth(), GraphicsHeight(), 6)
background.ClearPixels($ffffffff)
Local timer:TTimer = CreateTimer(60) Local x:Int = -1 Local y:Int = -1
While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
Local md:Int = MouseDown(1) Local mh:Int = MouseHit(1) If Not md And Not mh And x >= 0 And y >= 0 Then PIX_DrawLine(background, x, y, MouseX(), MouseY(), 255, 0, 0) x = -1 y = -1 ElseIf mh Then x = MouseX() y = MouseY() End If
If MouseHit(2) Then PIX_FloodFill(background, MouseX(), MouseY(),, 255, 127, 0) End If Cls
DrawPixmap(background, 0, 0) If x >= 0 And y >= 0 Then SetColor(255, 0, 0) DrawLine(x, y, MouseX(), MouseY()) SetColor(255, 255, 255) End If Flip 0 WaitTimer(timer) Wend
Function PIX_FloodFill(pixmap:TPixmap, x:Int, y:Int, schwellwert:Byte = 15, r:Byte, g:Byte, b:Byte, a:Byte = 255) If x < 0 Or y < 0 Or x >= pixmap.width Or y >= pixmap.height Then Return Local sr:Int, sg:Int, sb:Int, sa:Int GetColor_Parts(pixmap.ReadPixel(x, y), sr, sg, sb, sa)
Local isDone:Int[,] = New Int[pixmap.width, pixmap.height] isDone[x, y] = True Local color:Int = GetIntCol(r, g, b, a) Local worklist:TList = CreateList() worklist.AddLast(CreatePos(x, y)) Local dirX:Int[] = [- 1, 0, 1, 0] Local dirY:Int[] = [0, -1, 0, 1] Local p:TPosition Local tr:Int, tg:Int, tb:Int, ta:Int While worklist.IsEmpty() = 0 p = TPosition(worklist.RemoveFirst()) For Local i:Int = 0 Until 4 If p.x + dirX[i] >= 0 And p.x + dirX[i] < pixmap.width And p.y + dirY[i] >= 0 And p.y + dirY[i] < pixmap.height Then If Not isDone[p.x + dirX[i], p.y + dirY[i]] Then GetColor_Parts(pixmap.ReadPixel(p.x + dirX[i], p.y + dirY[i]), tr, tg, tb, ta) If Abs(tr - sr) < schwellwert And Abs(tg - sg) < schwellwert And Abs(tb - sb) < schwellwert And Abs(ta - sa) < schwellwert Then pixmap.WritePixel(p.x + dirX[i], p.y + dirY[i], color) worklist.AddLast(CreatePos(p.x + dirX[i], p.y + dirY[i])) End If isDone[p.x + dirX[i], p.y + dirY[i]] = True End If End If Next Wend End Function Function PIX_DrawLine(pixmap:TPixmap, x1:Int, y1:Int, x2:Int, y2:Int, r:Byte, g:Byte, b:Byte, a:Byte = 255, thickness:Int = 5) Local dx:Float = x2 - x1 Local dy:Float = y2 - y1 Local laenge:Float = Sqr(dx ^ 2 + dy ^ 2) If laenge = 0 Then If x1 >= 0 And y1 >= 0 And x1 < pixmap.width And y1 < pixmap.height Then pixmap.WritePixel(x1, y1, GetIntCol(r, g, b, a)) End If Return EndIf dx = dx / laenge dy = dy / laenge Local x:Float = x1 Local y:Float = y1 Local steps:Int = Ceil (laenge) Local i:Int = 0 Local color:Int = getIntCol(r, g, b, a) Local tmpcol:Int = color Local tr:Int, tg:Int, tb:Int, ta:Int While i < steps If x >= 0 And y >= 0 And x < pixmap.width And y < pixmap.height Then If a < 255 Then GetColor_Parts(pixmap.ReadPixel(x, y), tr, tg, tb, ta) tr = ((1.0 - (a / 256.0)) * tr) + ((a / 256.0) * r) tg = ((1.0 - (a / 256.0)) * tg) + ((a / 256.0) * g) tb = ((1.0 - (a / 256.0)) * tb) + ((a / 256.0) * b) ta = 255 tmpCol = GetIntCol(tr, tg, tb, ta) End If pixmap.WritePixel(x, y, tmpcol) End If x:+dx y:+dy i:+1 Wend If thickness > 1 Then Local normalX:Float = -dy Local normalY:Float = dx If Abs(normalX) > Abs(normalY) Then x = Sgn(normalX) y = 0 Else y = Sgn(normalY) x = 0 End If PIX_DrawLine(pixmap, x1 + normalX, y1 + normalY, x2 + normalX, y2 + normalY, r, g, b, a * 0.25, thickness - 2) normalX = dy normalY = -dx If Abs(normalX) > Abs(normalY) Then normalx = Sgn(normalX) normaly = 0 Else normaly = Sgn(normalY) normalx = 0 End If PIX_DrawLine(Pixmap, x1 + normalX, y1 + normaly, x2 + normalx, y2 + normaly, r, g, b, a * 0.5, thickness - 2) End If End Function
Function GetColor_Parts(intcolor:Int, r:Int Var, g:Int Var, b:Int Var, a:Int Var) a = (intcolor & $ff000000) Shr 24 r = (intcolor & $00ff0000) Shr 16 g = (intcolor & $0000ff00) Shr 8 b = (intcolor & $000000ff) End Function
Function GetIntCol:Int(r:Byte, g:Byte, b:Byte, a:Byte = 255) Local color:Int = 0 color:+a Shl 24 color:+r Shl 16 color:+g Shl 8 color:+b Return color End Function Type TPosition Field x:Int Field y:Int End Type
Function CreatePos:TPosition(x:Int, y:Int) Local pos:TPosition = New TPosition pos.x = x pos.y = y Return pos End Function
Steuerung: Linksklick + drag = linie setzen. Ist standartmäßig mit etwas größerer breite und festem farbwert (255,0,0) eingestellt. Ränder der linien werden "gesmoothed" um Schwellwert für floofill sichtbar zu machen.
Rechtsklick = Floodfill mit farbe 255,127,0. schwellwert ist standartmäßig 15.
Anmerkung: Da Bmx recht beschämend ist, was der zugriff auf den backbuffer ist und ich nicht umbedingt mit Plot und SetColor arbeiten wollte, mache ich das ganze in einer Pixmap. Im prinzip ist das ziel egal - solange man farbwerte lesen und schreiben kann.
Anmerkung2: Ich musste leider feststellen, das eine Floodfill funktion auf die schnelle wesentlich einfacher war, wie eine "sanfte linie mit größerer breite wie 1, welche im alphawert ausgefadet wird".
Generell die breite linie macht mir zu schaffen. So wies jetzt ist, siehts schräg aus. Gutes project für morgen: Very smoothed lines selber plotten Die idee existiert!
|