' This program exported from BASIC Anywhere Machine (Version [5.2.3].[2023.08.29.21.34]) on 2023.09.15 at 00:32 (Coordinated Universal Time)
' This BAM program, including the "TCIRCLE" subroutine, by Charlie Veniot
' Contributions by paul doe: "circle_Bresenham" and "circle_midpoint" FreeBASIC subroutines, ported by Charlie to BAM and tweaked for "aspect_ratio"

' "Triangle Math" important points:
'     * R is the right angle
'     * r is opposite side
'     * r squared = x squared + y squared

' "aspect_ratio" is the height of a pixel vs the width, width always being = 1; this is a BAM requirement for compatibility with GW-BASIC screen modes
 aspect_ratio = 1  ' so pixel height is 1 times pixel width for screen mode 12
' aspect_ratio = 2.4  ' so pixel height is 2.4 times pixel width for screen mode 8 in BAM and GW-BASIC
' aspect_ratio = 1.2  ' so pixel height is 1.2 times pixel width for screen mode 7 in BAM and GW-BASIC


DECLARE SUB circle_Charlie( xc as long, yc as long, r as long, c as LONG )
DECLARE SUB circle_Bresenham( xc as long, yc as long, r as long, c AS LONG )
DECLARE SUB circle_midpoint( xc as long, yc as long, r as long, c as LONG )

c_radius = 100
c1x = 10 + c_radius     : c1y = 18 + c_radius ' COLOR statement
c2x = 20 + c_radius * 3 : c2y = c1y           ' Charlie's TCIRCLE subroutine
c3x = 30 + c_radius * 5 : c3y = c1y           ' Paul's circle_Bresenham
c4x = 40 + c_radius * 7 : c4y = c1y           ' Paul's circle_midpoint
iterations = 0
cpi = 100
dim as double c1_time = 0, c2_time = 0, c3_time = 0, c4_time = 0, start_time = 0

SCREEN _NEWIMAGE(c_radius * 8 + 50, c_radius * 2 + 20, 12)

DO

    CLS

    start_time = timer
    FOR i = 1 TO cpi : CIRCLE (c1x, c1y), c_radius, 14 : NEXT i
    c1_time = c1_time + timer - start_time

    start_time = timer
    ' FOR i = 1 TO cpi : GOSUB TCIRCLE : NEXT i
    FOR i = 1 TO cpi : circle_Charlie( c2x, c2y, c_radius, 14 ) : NEXT i
    c2_time = c2_time + timer - start_time
   
    start_time = timer
    FOR i = 1 TO cpi : circle_Bresenham( c3x, c3y, c_radius, 14 ) : NEXT i
    c3_time = c3_time + timer - start_time
    
    start_time = timer
    FOR i = 1 TO cpi : circle_midpoint( c4x, c4y, c_radius, 14 ) : NEXT i
    c4_time = c4_time + timer - start_time

    iterations = iterations + cpi
    LOCATE 0,0
    PRINT "count: " + iterations + " circles drawn that many times for each method"
    LOCATE 8, 5 : PRINT "CIRCLE time: "     + INT(c1_time)     
    LOCATE 8, 31 : PRINT "Charlie's time: " + INT(c2_time)
    LOCATE 8, 57 : PRINT "Bresenham time: " + INT(c3_time)
    LOCATE 8, 83 : PRINT "Midpoint time: " + INT(c4_time)
    _display

LOOP

END

TCIRCLE: ' This GOSUB subroutine replaced by a SUB, for apples to apples performance comparison with the other subroutines.

    FOR xy = 0 TO c_radius*0.75
        a = SQR( c_radius * c_radius - xy * xy )
        a_ar = a/aspect_ratio
        xy_ar = xy/aspect_ratio
        PSET (c2x + xy, c2y - a_ar), 14
        PSET (c2x - xy, c2y - a_ar), 14
        PSET (c2x + xy, c2y + a_ar), 14
        PSET (c2x - xy, c2y + a_ar), 14
        PSET (c2x - a, c2y + xy_ar), 14
        PSET (c2x - a, c2y - xy_ar), 14
        PSET (c2x + a, c2y + xy_ar), 14
        PSET (c2x + a, c2y - xy_ar), 14
    NEXT xy

RETURN

sub circle_Charlie( xc as long, yc as long, r as long, c as LONG )
    DIM as long xy, a, a_ar, xy_ar
    
    FOR xy = 0 TO r*0.75
        a = SQR( r * r - xy * xy )
        a_ar = a/aspect_ratio
        xy_ar = xy/aspect_ratio
        PSET (xc + xy, yc - a_ar), 14
        PSET (xc - xy, yc - a_ar), 14
        PSET (xc + xy, yc + a_ar), 14
        PSET (xc - xy, yc + a_ar), 14
        PSET (xc - a, yc + xy_ar), 14
        PSET (xc - a, yc - xy_ar), 14
        PSET (xc + a, yc + xy_ar), 14
        PSET (xc + a, yc - xy_ar), 14
    NEXT xy

end sub

sub circle_Bresenham( xc as long, yc as long, r as long, c as LONG )
  dim as long x = 0, y = r
  dim as long d = 3 - 2 * r
  ' aspect_ratio approach 1
      dim as double yar = y/aspect_ratio
      dim as double xar = x/aspect_ratio
  ' aspect_ratio approach 2 (no improvement over approach 1)
      '  dim as double iAr = 1 / aspect_ratio ' Reciprocal of the aspect ratio
      '  dim as double yar = y*iAr
      '  dim as double xar = x*iAr
  
  pset( xc + x, yc + yar ), c
  pset( xc - x, yc + yar ), c
  pset( xc + x, yc - yar ), c
  pset( xc - x, yc - yar ), c
  pset( xc + y, yc + xar ), c
  pset( xc - y, yc + xar ), c
  pset( xc + y, yc - xar ), c
  pset( xc - y, yc - xar ), c
  
  do while( y >= x )
    x += 1
    
    if( d > 0 ) then
      y -= 1
      d = d + 4 * ( x - y ) + 10
    else
      d = d + 4 * x + 6
    end if

  ' aspect_ratio approach 1
      yar = y/aspect_ratio
      xar = x/aspect_ratio
  ' aspect_ratio approach 2 (no improvement over approach 1)
      ' yar = y * iar
      ' xar = x * iar
    
    pset( xc + x, yc + yar ), c
    pset( xc - x, yc + yar ), c
    pset( xc + x, yc - yar ), c
    pset( xc - x, yc - yar ), c
    pset( xc + y, yc + xar ), c
    pset( xc - y, yc + xar ), c
    pset( xc + y, yc - xar ), c
    pset( xc - y, yc - xar ), c
  loop
end sub

sub circle_midpoint( xc as long, yc as long, r as long, c as LONG )
  dim as long x = r, y = 0
  dim as double yar = y/aspect_ratio
  dim as double xar = x/aspect_ratio
  dim as byte bStayInDo = TRUE
  
  yar = y/aspect_ratio
  xar = x/aspect_ratio
  
  pset( -x + xc, yar + yc ), c
  pset( y + xc, -xar + yc ), c
  
  if( r > 0 ) then
    pset( x + xc, -yar + yc ), c
    pset( y + xc, xar + yc ), c
    pset( -y + xc, xar + yc ), c
  end if
  
  dim as long P = 1 - r
  
  do while( x > y ) AND bStayInDo
    y += 1
    
    if( P <= 0 ) then
      P = P + 2 * y + 1
    else
      x -= 1
      P = P + 2 * y - 2 * x + 1
    end if
    
    yar = y/aspect_ratio
    xar = x/aspect_ratio
    
    if( x < y ) then
        bStayInDo = FALSE
    ELSE
        pset( x + xc, yar + yc ), c
        pset( -x + xc, yar + yc ), c
        pset( x + xc, -yar + yc ), c
        pset( -x + xc, -yar + yc ), c
    
        if( x <> y ) then
            pset( y + xc, xar + yc ), c
            pset( -y + xc, xar + yc ), c
            pset( y + xc, -xar + yc ), c
            pset( -y + xc, -xar + yc ), c
        end if
    END IF
  loop
end sub