\ How to plot a circle?
\ hk  Oct 2026                Tested with noForth
\ Programmeeropgave van Albert Nijhof voor oktober 2026
\ See: http://forth-ig.nl/downloads/2026/Oktober/cirkel-opgave-an.pdf
\
\ Uses a 64 x 64 plotting grid, so now a circle with r = 23 can be plotted.
\ https://en.wikipedia.org/wiki/Midpoint_circle_algorithm#/media/File:Midpoint_circle_algorithm_radius_23.svg

decimal

64       constant SIDE          \ Size of one side of the plotting grid; max. r = 31
SIDE 2/  constant TLD           \ Translation distance
0  value    x
0  value    y
0  value    r2                  \ r squared
0  value    afw
0  value    afwZ                \ afwijking zuidwaarts
0  value    d                   \ decision variable, for algorithm CK2
0  value    t1
0  value    t2                  \ t1 & t2 temporary variables for algorithm CK3

create GRID  SIDE dup *  allot  \ Memory for a SIDE x SIDE plotting grid

: 4BITS    ( x -- x' )  hx 0F and ;                     \ 0F   = 15
: 5BITS    ( x -- x' )  hx 1F and ;                     \ 1F   = 31
: 6BITS    ( x -- x' )  hx 3F and ;                     \ 3F   = 63
: 10BITS   ( x -- x' )  hx 3FF and ;                    \ 3FF  = 1023
: 12BITS   ( x -- x' )  hx FFF and ;                    \ FFF  = 4095
: 16BITS   ( x -- x' )  hx FFFF and ;                   \ FFFF = 65535

: 6BNEGATE ( x -- -x )  negate 6bits ;                  \ 6 bits negate

: CLEAR    (   --    )  grid  SIDE dup *  bl fill ;     \ Clear the grid with blanks

: POS>ADR  ( pos -- adr   )  12bits grid + ;
: TRANSL   (   n -- n'    )  TLD +  SIDE 1- and ;       \ Translation for grid origin
: XY>HV    ( x y -- h v   )  transl swap transl swap ;  \ Origin to grid centre     
: HV>ADR   ( h v -- adres )  6 lshift +  pos>adr ;

: PLOT     ( x y -- )  xy>hv hv>adr ch @ swap c! ;
: PLOT+    ( x y -- )  >r      \ Plot 4 points in 4 quadrants of a circle 
    dup r@ plot   dup r@ 6bnegate plot            \ (x,y)    (x,-y)
    6bnegate
    dup r@ plot   r> 6bnegate plot ;              \ (-x,y)   (-x,-y)
: PLOT8    ( x y -- )          \ Plot 8 points in 8 octants of a circle
    2dup plot+   swap plot+ ;  \ also: (y,x)  (-y,x)  (-y,x)  (-y,-x)


\ ---------- Print the upside down Cartesian grid (no problem for circles)
: SPEMIT  ( ch -- )        space emit ;                  \ type a space and a character
: SPTYPE  ( a n -- )       FOR count spemit NEXT drop ;  \ type n spaced chars of string a
: .GRID ( -- )                                           \ Print the grid
    grid side    (           -- adr n     )
    FOR          ( adr n     -- adr       ) 
      dup side   ( adr       -- adr adr n ) 
      cr sptype  ( adr adr n -- adr       ) 
      side +     ( adr       -- adr+n     )
    NEXT drop ;
: .GRID ( -- )                                           \ Print the grid (for AN)
    grid  side FOR  dup side  cr sptype  side +  NEXT  drop ;    

\ ---------- Circle plotting algorithms
: <=   > 0= ;
: CK0  ( r -- )         \ Plot a circle with radius r, using the hints of AN.
    clear               \   This is all I could figure out. 7 CK0 looks OK, but as 9 CK0 
    to y                \   produces an octagon I don't think it is optimal.
    0 to x
    0 to afw
    
    x y plot8
    BEGIN x y <= WHILE
      x 1+ to x       \ stap oostwaarts
      x y plot8
      x dup + 1 + afw      +  to afw
      y dup + 1 - afw swap -  to afwZ
      afwZ abs  afw abs  <  IF
        y 1- to y   \ stap zuidwaarts
        y dup + 1 - afw swap -  to afw
      THEN
    REPEAT 
    .grid ;
    
: CK  ( r -- )          \ Plot a circle with radius r, Bresenham midpoint algorithm.
    clear               \   I guess this is optimal, but I would not know how to derive 
    0 to x              \   this from the hints of AN.
    dup to y            \ r to y
    dup * to r2         \ r squared to r2
    
    BEGIN x y <= WHILE
      x y plot8
      x 1+ to x
      x dup *  y dup * +  r2 -  abs  to afw
      x dup *  y 1- dup *  +  r2 -  abs  to afwZ
      afwZ afw < IF
        y 1- to y
      THEN
    REPEAT 
    .grid ;
    
: CK2 ( r -- )           \ Plot a circle with radius r, Bresenham midpoint algorithm.
    clear                \   Another implementation of the same algorithm.
    dup to y
    0 to x
    3 swap dup + - to d  \ d is decision variable; initially d = 3 - 2r
   
    BEGIN x y <= WHILE
      x y plot8
      d 0 < IF
        d x 4 * + 6 + to d
      ELSE  \ d >= 0
        d x y - 4 * + 10 + to d
        y 1- to y
      THEN
      x 1+ to x
    REPEAT 
    .grid ;
   
: >=   < 0= ;
: CK3 ( r -- )          \ Plot a circle with radius r
    \ Jesko's method of the Bresenham midpoint algorithm.  Interesting but probably
    \ not optimal.  Works quite good for larger circles ( r > 8 ).
    clear                
    dup 16 / to t1       \ r/16 to t1
    to y                 \ r to y
    0 to x
   
    BEGIN y x >= WHILE
      x y plot8
      x 1+ to x
      t1 x + to t1
      t1 y - to t2
      t2 0 >= IF
        t2 to t1
        y 1- to y
      THEN
    REPEAT 
    .grid ;
   
: 7CK                   \ Plot a circle with radius 7
    clear
    0 7 plot8   1 7 plot8   2 7 plot8  
    3 6 plot8   4 6 plot8   5 5 plot8 
    .grid ;

