Seite 1 von 1

Circle selfmade

Verfasst: 27.03.2009 17:48
von cxAlex
Aufgrund eines Posts im englischen Forum hab ich mich an einer Circle() Procedure versucht. Nun ist sie leicht langsamer als die von PB. auch erkennt man das PB einen etwas anderen Algo verwenden muss, hat jemand eine Idee?:

Code: Alles auswählen

Procedure _Circle(x0, y0, rad, color = 0)
  Static x, y, rad2
  
  rad2 = rad*rad
  
  x = 0
  y = 1
  
  Plot(x0, y0 + rad, color)
  Plot(x0, y0-rad, color)
  Plot(x0 + rad, y0, color)
  Plot(x0-rad, y0, color)
  
  While x<y
    
    x + 1
    y = Sqr(rad2-x*x)
    
    Plot(x0-x, y0-y, color)
    Plot(x0-x, y0 + y, color)
    Plot(x0 + x, y0-y, color)
    Plot(x0 + x, y0 + y, color)
    Plot(x0-y, y0-x, color)
    Plot(x0-y, y0 + x, color)
    Plot(x0 + y, y0-x, color)
    Plot(x0 + y, y0 + x, color)
    
  Wend
  
  
EndProcedure

OpenWindow(0, 0, 0, 450, 450, "demo", #PB_Window_SystemMenu)

#cnt = 100

If StartDrawing(WindowOutput(0))
    

    t = ElapsedMilliseconds()
    For i = 1 To #cnt
      _Circle(120, 225, i, $ff)
    Next
    t1 = ElapsedMilliseconds()-t
    DrawingMode(#PB_2DDrawing_Outlined)
    
    DrawingMode(#PB_2DDrawing_Outlined)
    t = ElapsedMilliseconds()
    For i = 1 To #cnt
      Circle(345, 225, i, $ff)
    Next
    t2 = ElapsedMilliseconds()-t
    
    
  StopDrawing()
EndIf

MessageRequester("str", Str(t1) + Chr(13) + Str(t2))

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow

Verfasst: 27.03.2009 18:42
von STARGÅTE
da man bei sehr großen kreisen keinen unterschied mehr sieht ob es ein VielEck oder Kreis ist, mach ich das zB mit Lines:

Code: Alles auswählen

Procedure _Circle(x0, y0, rad, color = 0) 
  Static x1,x2,y1,y2, n=0, line=50
  factor.f = 1/line*2*#PI
  x1 = x0+rad
  y1 = y0+0
  For n = 1 To line
   x2 = x0+Cos(n*factor)*rad
   y2 = y0+Sin(n*factor)*rad
   LineXY(x1,y1,x2,y2,Color)
   x1 = x2
   y1 = y2
  Next  
EndProcedure
ist auf jedenfall schon mal schneller als das plotten ^^
aber kommt leider nicht an PB ran ...
man könnte aber noch zeit gut machen, wenn man bei kleinen kreisen weniger line nimmt ...

Verfasst: 27.03.2009 19:17
von cxAlex
Auch eine Methode Stargate. Nur muss man bei großen Kreisen die Anzahl der Linien manuell erhöhen (ein Kreis mit Radius 800 sieht damit schon komisch aus).

Dieser Code ist bei mir jetzt immer gleichschnell bis leicht schneller als PB, ich bin zufrieden :D

Code: Alles auswählen

Procedure _Circle(x0, y0, rad, color = 0)
  Static x, y, rad2, oldcolor
  
  oldcolor = FrontColor(color)
  rad2 = rad*rad
  x = 0
  
  Plot(x0, y0 + rad)
  Plot(x0, y0-rad)
  Plot(x0 + rad, y0)
  Plot(x0-rad, y0)
  
  Repeat
    
    x + 1
    y = Sqr(rad2-x*x)
    
    Plot(x0-x, y0-y)
    Plot(x0-x, y0 + y)
    Plot(x0 + x, y0-y)
    Plot(x0 + x, y0 + y)
    Plot(x0-y, y0-x)
    Plot(x0-y, y0 + x)
    Plot(x0 + y, y0-x)
    Plot(x0 + y, y0 + x)
    
  Until x>y
  
  FrontColor(oldcolor)
  
EndProcedure

OpenWindow(0, 0, 0, 650, 450, "demo", #PB_Window_SystemMenu)

#cnt = 1000

If StartDrawing(WindowOutput(0))
    
    
    t = ElapsedMilliseconds()
    For i = 1 To #cnt
      _Circle(110, 225, i, $ff)
    Next
    t1 = ElapsedMilliseconds()-t
    DrawingMode(#PB_2DDrawing_Outlined)
        
    DrawingMode(#PB_2DDrawing_Outlined)
    t = ElapsedMilliseconds()
    For i = 1 To #cnt
      Circle(545, 225, i, $ff)
    Next
    t3 = ElapsedMilliseconds()-t
    
    
  StopDrawing()
EndIf

MessageRequester("str", "cxAlex: "+Str(t1) + Chr(13) +"PB: "+Str(t3))

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow

Verfasst: 27.03.2009 19:24
von Kaeru Gaman
@STARGÅTE

LineXY() ist wesentlich langsamer als Line(), weil sie extra noch den abschließenden Punkt plottet.
die einfache Line() zu verwenden sollte einen deutlichen Vorteil bringen, selbst wenn man eine Differenz errechnen muss.

außerdem spart es irre zeit, eine vorgefertigte Sinustabelle zu benutzen,
anstatt der nativen FPU-Funktionen:
http://www.purebasic.fr/german/viewtopic.php?t=5884

Verfasst: 06.04.2009 22:29
von NicTheQuick
Ihr solltet euch das hier mal anschauen: Kreise zeichnen mit Turbo

Da braucht man weder eine Sinus, noch Wurzel, noch Quadratzahlen. Nur Plus und Mal.

Der Rest der Seite dürfte für den ein oder anderen auch interessant sein.

Verfasst: 07.04.2009 07:31
von Helle
Mit Bresenham hatte ich auch experimentiert (nur Kreis-Umfang):

Code: Alles auswählen

Procedure Bresenham(X0, Y0, Radius, Color) 
  F = 1 - Radius    
  Plot(X0, Y0 + Radius, Color)
  Plot(X0 + Radius, Y0, Color)
  Plot(X0, Y0 - Radius, Color)
  Plot(X0 - Radius, Y0, Color)
  Y = Radius
  While X < Y    
    X + 1    
    If F < 0    
      F = F + (X << 1) - 1    
     Else    
      F = F + (X - Y) << 1    
      Y - 1    
    EndIf    
    X2 = X0 + X
    Y2 = Y0 + Y
    X3 = X0 - X
    Y3 = Y0 - Y
    Plot(X2, Y2, Color)
    Plot(Y2, X2, Color)
    Plot(X3, Y2, Color)
    Plot(Y3, X2, Color)
    Plot(X2, Y3, Color)
    Plot(Y2, X3, Color)
    Plot(X3, Y3, Color)
    Plot(Y3, X3, Color)
  Wend    
EndProcedure 


OpenWindow(0, 0, 0, 400, 400, "Bresenham-Kreis", #PB_Window_SystemMenu) 
  If StartDrawing(WindowOutput(0))
    Bresenham(200, 200, 150, 255) 
    StopDrawing()
  EndIf
  Repeat 
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow
CloseWindow(0)
Ist aber (bei mir) langsamer! Der Grund dürfte sein, dass auf modernen CPU´s für SQR() nur noch ca. 6 CPU-Taktzyklen benötigt werden.
Zum Thema Geschwindigkeit: Ich wollte hier ja auch was zum Besten geben (schneller als die anderen obigen Vollkreis-Codes), habe dann testweise das Ganze auf meinem (3-Jahre alten Notebook) laufen lassen und siehe da, auf dem Notebook (On-Board-Intel-Grafik) war PB wieder wesentlich schneller! Habe dann entnervt aufgegeben... :mrgreen:

Gruß
Helle