Linienalgorithmus

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

darth

Betreff: Linienalgorithmus

BeitragMi, Sep 26, 2007 15:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Hier ist ein (einfacher) Algorithmus um Linien schneller zu zeichnen. Es bietet eine Alternative zum "Original" hier http://www.blitzbase.de/quellcode/bresenham.bb.
Code: [AUSKLAPPEN]
Function Linie(x1#,y1#,x2,y2,r,g,b)
 farbe=r*$10000+g*$100+b
 vx#=x2-x1 : vy#=y2-y1
 l#=Sqr(vx^2+vy^2)
 vx=vx/l : vy=vy/l
 Repeat
  WritePixelFast x1,y1,farbe
  x1=x1+vx
  y1=y1+vy
 Until Int(x1)=x2 And Int(y1)=y2
End Function

Natürlich darf man nicht vergessen vorher den Buffer zu locken, die Anwendung sähe also wie folgt aus:
Code: [AUSKLAPPEN]
Graphics 800,600
setbuffer backbuffer()

Lockbuffer(backbuffer())
 linie 0,0,800,600
unlockbuffer(backbuffer())
flip 0

waitkey()

Wie auch immer, dieser Code dient "nur" dazu, Linien zu zeichnen. Er ersetzt keine Füllfunktionen, wie zum Beispiel Kreise. Für solches sollte man den Algorithmus aus dem Link verwenden.

PS:
wer gestrichelte Linien möchte kann den hier verwenden:
Code: [AUSKLAPPEN]
Function Linie(x1#,y1#,x2,y2,s,r,g,b)
 farbe=r*$10000+g*$100+b
 vx#=x2-x1 : vy#=y2-y1
 l#=Sqr(vx^2+vy^2)
 vx=vx/l : vy=vy/l
 Repeat
  If m<=s Then WritePixelFast x1,y1,farbe
  x1=x1+vx
  y1=y1+vy
  m=m+1
  If m>=2*s Then m=0
 Until Int(x1)=x2 And Int(y1)=y2
End Function


[EDIT, 11.04.2010]

Hallo,

jaja, heute sehe ich ziemlich schnell ein, dass ein Algorithmus mit Wurzel und FloatingPoint Operation nicht wirklich schnell sein kann. Einzig der Code für die "gestrichelte" Linie ist wahrscheinlich sinnvoll :> Aber das zu beurteilen sei anderen überlassen. Ich habe gerade gesehen, dass der verlinkte Code nichtmehr vorhanden ist, also habe ich beschlossen, einen Bresenham kurz selber zu schreiben. Es ist eigentlich gar nicht derart schwer, v.a weil [url=http://en.wikipedia.org/wiki/Bresenham's_line_algorithm]Wikipedia[/url] einen ziemlich guten/einfach zu verstehenden Ansatz liefert.

BlitzBasic: [AUSKLAPPEN]
Function BLine(x0, y0, x1, y1)
Local col=ColorRed()*$10000+ColorGreen()*$100+ColorBlue()

Local dX, dY, y, x
Local err#, dErr#

dX=x1-x0
dY=y1-y0

If dX<>0

dErr=dY/dX

y=y0

For x=x0 To x1
;WritePixel x,y,col
WritePixelFast x,y,col

err=err+dErr

If Abs(err)>=0.5
y=y+1
err=err-1
EndIf
Next

ElseIf dY<>0

dErr=dX/Float(dY)

x=x0

For y=y0 To y1
;WritePixel x,y,col
WritePixelFast x,y,col

err=err+dErr

If Abs(err)>=0.5
x=x+1
err=err-1
EndIf
Next

EndIf
End Function


Der Code (funktioniert übrigens nur für Spezialfälle..) liest die gesetzte Bildschirmfarbe aus und färbt die Linie danach. Standardmässig wird mit WritePixelFast gezeichnet, das heisst, vor dem Zeichnen der Linie, muss man den Buffer mit LockBuffer versiegeln.
Im Anschluss habe ich dann noch einige Geschwindigkeitstests gemacht, das Ergebnis ist eigentlich recht befriedigend. Line im Lockbuffer Modus ist etwa doppelt so schnell wie Bresenham (wahrscheinlich weil BB intern damit arbeitet..). Bresenham (ebenfalls Lockbuffer) folgt mit etwa der doppelten Zeit, und dann etwas langsamer Line ohne Lockbuffer.
Die Zeiten sind im 1000stel MS Bereich für einen Aufruf (gemessen 5000 Aufrufe, dividiert), da hat man ziemlich schwankende Ergebnisse, aber es sollte trotzdem repräsentativ sein.

Der TestCode:

BlitzBasic: [AUSKLAPPEN]
Graphics 800,600,0,2
SetBuffer BackBuffer()

While Not KeyHit(1)

; Std Line Lockbuffer:

Color 255,255,255

LockBuffer BackBuffer()

tick=MilliSecs()
For x=0 To 5000
Line 10,10,100,100
Next
tock=MilliSecs()

UnlockBuffer BackBuffer()

Text 200,10,"Lockbuffer Line: "+(tock-tick)/5000.

; Bresenham Line:

Color 255,255,255

LockBuffer BackBuffer()

tick=MilliSecs()
For x=0 To 5000
BLine 10,10,100,100
Next
tock=MilliSecs()

UnlockBuffer BackBuffer()

Text 200,30,"BLine: "+(tock-tick)/5000.

; Std Line:

Color 255,255,255

tick=MilliSecs()
For x=0 To 5000
Line 10,10,100,100
Next
tock=MilliSecs()

Text 200,50,"Line: "+(tock-tick)/5000.

Flip 0
Cls
Wend
End


So im Abschluss kann ich eigentlich nur sagen: Benutzt die originale BB Line im Lockbuffer Modus, es ist eigentlich mit Abstand das Schnellste! Und auch aus Erfahrung kann ich sagen, dass man damit eigentlich Bildschirmfüllend zeichnen kann (Beispiel). Dieses Ergebnis macht diesen Thread eigentlich absolut sinnlos. Einzig ein wenig Vektorgeometrie und der Bresenham Algorithmus werden hier dargestellt, deren Verwendung sich in BB nicht lohnt.

Auf der Seite wird ebenfalls eine allgemeine und optimierte Version erklärt. Dort hat man keinerlei Float Operationen mehr, es wird alles mit Integern gelöst. Das führt zu einer erhöhten Geschwindigkeit. Der optimierte Algorithmus ist etwa gleich schnell, bis ein kleines bisschen langsamer als die native BB Linie. Der Vollständigkeit wegen sei er aber trotzdem hier eingefügt:

BlitzBasic: [AUSKLAPPEN]
Function OBLine(x0, y0, x1, y1)
Local col=ColorRed()*$10000+ColorGreen()*$100+ColorBlue()

Local steep
Local tmp, dX, dY, err, yStep, y

If Abs(y1-y0)>Abs(x1-x0)
steep=True

tmp=x0
x0=y0
y0=tmp

tmp=x1
x1=y1
y1=tmp
Else
steep=False
EndIf

If x0>x1
tmp=x0
x0=x1
x1=tmp

tmp=y0
y0=y1
y1=tmp
EndIf

dX=x1-x0
dY=Abs(y1-y0)
err=dX/2
y=y0

If y0<y1
yStep=1
Else
yStep=-1
EndIf

For x=x0 To x1
If steep
WritePixelFast y,x,col
Else
WritePixelFast x,y,col
EndIf

err=err-dY

If err<0
y=y+yStep

err=err+dX
EndIf
Next
End Function


Es bleibt also dabei: Benutzt die original Linie im Lockbuffer Modus und ihr habt keine Probleme. So mache ich es eigentlich immer.

In dem Sinne:
MfG,
Darth
  • Zuletzt bearbeitet von darth am So, Apr 11, 2010 16:11, insgesamt 4-mal bearbeitet

pixelshooter

BeitragDo, Sep 27, 2007 0:46
Antworten mit Zitat
Benutzer-Profile anzeigen
darf man fragen, warum x1 und y1 float sind?
>> Musikerstellung, Grafik und Design: http://www.pixelshooter.net.tc

darth

BeitragDo, Sep 27, 2007 11:18
Antworten mit Zitat
Benutzer-Profile anzeigen
weil vx und vy floats sind
und es tut sich schwert int+float zu addieren,
so kann es (bei ungünstigen fällen) zu einer endlosschleife und somit zu einem stack overflow kommen, weil die ints nie grösser werden... (und die schleife nie beendet wird) daher float.
Diese Signatur ist leer.

Xeres

Moderator

BeitragDo, Sep 27, 2007 14:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Warum ist Lockbuffer nicht in der Funktion integriert? Kommt's da zu Geschwindigkeitseinbußen wenn man den Buffer immer Locked/unkocked ?
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
 

#Reaper

Newsposter

BeitragDo, Sep 27, 2007 16:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Xeres hat Folgendes geschrieben:
Warum ist Lockbuffer nicht in der Funktion integriert? Kommt's da zu Geschwindigkeitseinbußen wenn man den Buffer immer Locked/unkocked ?


Jop, deine Annahme ist richtig Wink
AMD Athlon 64 3500+, ATI AX800 Pro/TD, 2048 MB DRR 400 von Infineon, ♥RIP♥ (2005 - Juli 2015 -> sic!)
Blitz3D, BlitzMax, MaxGUI, Monkey X; Win7

maximilian

BeitragDo, Sep 27, 2007 16:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Ja. Jeder Lock-Aufruf ist eine teure Sache. Du solltest es so managen, pro Schleifendurchlauf nur 1x zu locken, weil anscheinend der gesamte Bildschirminhalt dafür intern von DirectDraw kopiert werden muss.

/edit: argh, zu spät
Variety is the spice of life. One day ignore people, next day annoy them.
 

Matthias

BeitragDo, Sep 27, 2007 16:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Hay. Also ich kann mir das kaum vorstellen das deine Function schneller ist. Schon alleine wegen der sqr function und den Floats. Aber es kann natürlich gut möglich sein. Deshalb würde ich es mir wünschen wenn du mal tatsächlich einen Code schreibst der beide functionen gegenüberer stellt,
und den Geschwindigkeits-Unterschied in Prozente angibt.

BladeRunner

Moderator

BeitragDo, Sep 27, 2007 16:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn es Dich interessiert bist Du gerne eingeladen selbst einen Test zu verfassen.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

Progger93

Betreff: Linie ist Langsamer

BeitragDo, Sep 27, 2007 17:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich hab's mal getestet und bin zu folgendem ergebnis gekommen:

nach 5000 durchläufen
-line: 704
-linie: 217

Code: [AUSKLAPPEN]

Graphics 640,480,16,1
SetBuffer BackBuffer()

start1=MilliSecs()
For I=0 To 5000
 Line 0,0,640,480
Next
gesamt1=MilliSecs()-start1

start2=MilliSecs()

LockBuffer(BackBuffer())
For I=0 To 5000
 Linie(0,0,640,480,255,255,255)
Next
UnlockBuffer(BackBuffer())

gesamt2=MilliSecs()-start2

Print "Line: "+gesamt1
Print "Linie: "+gesamt2
WaitKey
End

Function Linie(x1#,y1#,x2,y2,r,g,b)
farbe=r*$10000+g*$100+b
vx#=x2-x1 : vy#=y2-y1
l#=Sqr(vx^2+vy^2)
vx=vx/l : vy=vy/l
Repeat
WritePixelFast x1,y1,farbe
x1=x1+vx
y1=y1+vy
Until Int(x1)=x2 And Int(y1)=y2
End Function
MfG Pascal
Win 7|T7250@2.0Ghz|3GB RAM|M8600GT
  • Zuletzt bearbeitet von Progger93 am Do, Sep 27, 2007 17:22, insgesamt 2-mal bearbeitet

BladeRunner

Moderator

BeitragDo, Sep 27, 2007 17:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Du machst Linie nur leider 5000 statt 500 mal. Congrats.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

Progger93

BeitragDo, Sep 27, 2007 17:21
Antworten mit Zitat
Benutzer-Profile anzeigen
sry hab ich übersehen ich werds mal anders versuchen
MfG Pascal
Win 7|T7250@2.0Ghz|3GB RAM|M8600GT

BladeRunner

Moderator

BeitragDo, Sep 27, 2007 17:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich hab das ganze auch nochmal Durchlaufen lassen und erziehle ähnliche Ergebnisse - Bresenham gewinnt bei je 5000 Durchläufen mit 240 vor Line mit 270 und Darth mit 450 ms.
Bresenham jedoch musste ich um den letzten Pixel kürzen, da hier trotz lockbuffer der letzte Pixel (writepixelfast x2,y2,rgb) zu einem MAV führte.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

Matthias

BeitragDo, Sep 27, 2007 17:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Naja konnte ich mir schon fast denken. Und ich finde wenn der Code so langsamm ist gegenüber bresenham und sogar noch der Standertlinie dann gehört er nicht hier rein.

Eingeproggt

BeitragDo, Sep 27, 2007 17:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn man so fair ist, und den Buffer auch für den Line-Versuch locked, ist Line noch fast doppelt so schnell.
Bei mir 240, danach 135ms.

Die Version von Darth ist leider wirklich mit Abstand die langamste, aber er hat ne recht einfache Methode eingebaut, um sie strichliert zu machen, ich würds deshalb im Codearchiv lassen.
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9

darth

BeitragFr, Sep 28, 2007 16:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Nach den vielen Ansichten dass mein Algorithmus langsam(er) sei, wollte ich das natürlich selber nachprüfen. Und es stimmt, - teilweise - !
Für lange Linien eignet sich gewiss der eingebaute Line Befehl (je 5000 Linien von 0,0 bis 800,600: Line=600 / Linie=1800).
Jetzt ein ABER, für kurze Linien eignet sich mein Algorithmus scheinbar besser. Wieder je 5000 linien, diesmal von 0,0 bis 50,50: Line=171 / Linie=133.
Dieser Vorteil ist aber schnell aufgebraucht und erreicht schon bei ca 0,0,100,100 die Stufe, dass Line wieder besser wird.
(Da Bresham so ausser Konkurenz steht hab ich den gar nicht mitgetestet, ich glaube euch dass er besser ist Razz)

Fazit daraus:
Wer sehr kurze Linien braucht ist mit meinem Algorithmus sicherlich nicht schlecht beraten, für lange Linien ist davon abzuraten und auf den eingebauten Befehl zu schwenken oder ganzzeitlich Bresham einzusetzen.

PS: Die Testcodes:
Code: [AUSKLAPPEN]
start1=MilliSecs()
 For k=0 To 5000
  Color 255,255,255 : Line 0,0,50,50
 Next
 Flip 0
stop1=MilliSecs()

start2=MilliSecs()
LockBuffer(BackBuffer())
 For k=0 To 5000
  linie 0,0,50,50,255,255,255
 Next
UnlockBuffer(BackBuffer())
 Flip 0
stop2=MilliSecs()
Diese Signatur ist leer.

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group