Drawing Empty Circles
Monkey Forums/Monkey Programming/Drawing Empty Circles| 
 | ||
| In Monkey DrawCirle, DrawEllipse or DrawOval functions fill the shapes. I need to draw empty circles and I did the following code: The only problem it is the performance. Is there another way to draw empty circles in Monkey?  Method Circle:Void(x:Float, y:Float, w:Float, h:Float)
    For Local phi:Float = 0.0 Until 360.0
        DrawPoint(x + Cos(phi) * w, y - Sin(phi) * h)
    Next
End
 | 
| 
 | ||
| Maybe something like: Method Circle:Void(x:Float, y:Float, w:Float, h:Float)
    For Local phi:Float = 0.0 Until 360.0 Step 10
        DrawLine(x + Cos(phi-10) * w, y - Sin(phi-10) * h, x + Cos(phi) * w, y - Sin(phi) * h )
    Next
End
Untested, but you're basically drawing 36 short lines, instead of 360 points. | 
| 
 | ||
| http://en.wikipedia.org/wiki/Midpoint_circle_algorithm | 
| 
 | ||
| Guys thank you , It improved the performance | 
| 
 | ||
| The simplest thing is to make a Polygon function that draws a polygon of N points, starting at a certain angle.  Then for a circle, you just use lots of points. Of course if the background is unimportant, you can DrawCircle twice in different colours, with the second one having a smaller radius. | 
| 
 | ||
| Translated my old PureBasic code for Bresenham circle and ellipse: Strict
Import mojo
Function Circle:Void(x:Int, y:Int, radius:Int)
    Local temp_x:Int = 0
    Local d:Int      = 3 - 2 * radius
    
    While temp_x <= radius
        DrawPoint(x+temp_x, y+radius) ' part 1
        DrawPoint(x-temp_x, y+radius)
        DrawPoint(x+radius, y+temp_x) ' part 2
        DrawPoint(x-radius, y+temp_x)
        DrawPoint(x+radius, y-temp_x) ' part 3
        DrawPoint(x-radius, y-temp_x)
        DrawPoint(x-temp_x, y-radius) ' part 4
        DrawPoint(x+temp_x, y-radius)
        
        If d < 0
            d += 4 * temp_x + 6
        Else
            d += 4 * (temp_x - radius) + 10
            radius -= 1
        Endif
        temp_x += 1
    Wend
End
Function Ellipse:Void(x:Int, y:Int, radius_x:Int, radius_y:Int)
    Local temp_x:Int         = 0
    Local temp_y:Int         = radius_y
    Local temp_radius_x1:Int = radius_x * radius_x
    Local temp_radius_y1:Int = radius_y * radius_y
    Local temp_radius_x2:Int = temp_radius_x1 * 2
    Local temp_radius_y2:Int = temp_radius_y1 * 2
    Local temp_fx:Int        = 0
    Local temp_fy:Int        = temp_radius_x2 * radius_y
    Local p:Int              = temp_radius_y1 - temp_radius_x1*radius_y + Int(0.25 * temp_radius_x1)
    
    If radius_x = radius_y
        Circle(x,y,radius_x)
        Return
    Endif
    
    While temp_fx <= temp_fy
        DrawPoint(x+temp_x, y+temp_y)
        DrawPoint(x-temp_x, y+temp_y)
        DrawPoint(x-temp_x, y-temp_y)
        DrawPoint(x+temp_x, y-temp_y)
        
        temp_x += 1
        temp_fx += temp_radius_y2
        If p < 0
            p += temp_fx + temp_radius_y1
        Else
            temp_y  -= 1
            temp_fy -= temp_radius_x2
            p       += temp_fx + temp_radius_y1 - temp_fy
        Endif
    Wend
    DrawPoint(x+temp_x, y+temp_y)
    DrawPoint(x-temp_x, y+temp_y)
    DrawPoint(x-temp_x, y-temp_y)
    DrawPoint(x+temp_x, y-temp_y)
    
    p = temp_radius_y1 * (temp_x - 0.5) * (temp_x + 0.5) + temp_radius_x1 * (temp_y - 1)*(temp_y - 1) - temp_radius_x1 * temp_radius_y1
    
    While temp_y > 0
        temp_y -= 1
        temp_fy -= temp_radius_x2
        If p >= 0
            p -= temp_fy + temp_radius_x1
        Else
            temp_x += 1
            temp_fx += temp_radius_y2
            p += temp_fx - temp_fy + temp_radius_x1
        Endif
        
        DrawPoint(x+temp_x, y+temp_y)
        DrawPoint(x-temp_x, y+temp_y)
        DrawPoint(x-temp_x, y-temp_y)
        DrawPoint(x+temp_x, y-temp_y)
        
    Wend
End
Function RotateAt:Void(x:Float, y:Float, angle:Float)
    Translate(x, y)
    Rotate(angle)
    Translate(-x, -y)
End
Class Program Extends App
    Field rotation:Float = 0
    Method OnCreate:Int()
        SetUpdateRate 60
        Return 0
    End
    Method OnRender:Int()
        Local mid_x:Int = DeviceWidth()  * 0.5
        Local mid_y:Int = DeviceHeight() * 0.5
        Cls 128,128,128
        SetColor 0,0,0
        Circle mid_x, mid_y,40
        RotateAt(mid_x,mid_y,rotation)
        rotation += 5
        'SetColor 255,255,255
        'DrawEllipse mid_x, mid_y,100,60
        'SetColor 0,0,0
        For Local i:Int = 60 To 150 Step 5
            Ellipse mid_x, mid_y,40+i,i
        Next
        Return 0
    End
End
Function Main:Int()
    New Program
    Return 0
End | 
| 
 | ||
| Function DrawCircleOutline:Void(x:Float, y:Float, radius:Float, detail:Int = -1) If detail < 0 detail = radius / 2.0 ElseIf detail < 3 detail = 3 ElseIf detail > MAX_VERTS detail = MAX_VERTS End Local angleStep:Float = 360.0 / detail Local angle:Float Local offsetX:Float Local offsetY:float Local first:Bool = True Local firstX:Float Local firstY:float Local thisX:Float Local thisY:float Local lastX:Float Local lastY:Float For Local vertIndex:= 0 Until detail offsetX = Sin(angle) * radius offsetY = Cos(angle) * radius If first first = False firstX = x + offsetX firstY = y + offsetY lastX = firstX lastY = firstY Else thisX = x + offsetX thisY = y + offsetY DrawLine(lastX, lastY, thisX, thisY) lastX = thisX lastY = thisY EndIf angle += angleStep Next DrawLine(lastX, lastY, firstX, firstY) End You can leave the detail parameter out if you just want to draw a circle. detail is the number of lines that will be drawn so you can draw polygons with this function too. | 
| 
 | ||
| Bresenham performs in most cases faster and better, because it draws the exact amount of pixels which is necessary to close the radius. Only on very big circles you will see advantages with a 5°-steps method. Additional you can speed up this method, because you never need to draw all 360° as you see in the Bresenham. Also the 5°-steps method will be faster if you only draw 45° and mirror all this results 8 times. | 
| 
 | ||
| Bresenham does not use Sin() and Cos(). If you draw 72 lines for 5° steps, each line is still made up of points, so I think the Bresenham Circle is the simplest. The amount of points required to draw a 360° circle shouldn't differ much. You just can't take fewer points for the same closed circle. Could be an advantage when the lines/points get drawn with hardware acceleration, if available for a specific targets. | 
| 
 | ||
| And pre-creating a float array of a circle-like polygon and drawing it using DrawPoly with the given translate and scale? wouldn't this be faster taking into account that it is pre-calculated? | 
| 
 | ||
| The only bit that's precalculated is the initial positions. You're still translating and scaling each time. The actual polygon draw might well be faster though. I think everyone is getting a bit carried away here with theorising. As usual, Monkey is a cross-platform language. What's fast on one target may be slow on another. Also, this isn't 1990 so just thinking about CPU and avoiding trig isn't necessarily going to find the fastest method considering the way GL rendering works. Frankly, unless you're going circle crazy I doubt there's much noticeable difference between a doing some trig and getting a reasonable number of lines and doing Bresenham's on most of the targets. | 
| 
 | ||
| On HTML5 I created a native line circle function using the built in arc method. Seems very nippy. | 
| 
 | ||
|  I think everyone is getting a bit carried away here with theorising. Yes! That's fun! |