Outline; Filled; Arc; Sector; Segment - 2094 bytes (12.7%)


§1. Types of circle routines available.

circles_chart.png

§2. Plot the outline of a circle.

 The circle is specified by two points, the centre point and a point on the radius.

 On Entry:
   .vduGraphicsCursorPixelsXLow:   centre point    [4 bytes]
   .vdu25ParameterXLow:            point on radius [4 bytes]
.plotCircleOutline = $9044
    Copy the centre of the circle point to the old graphics position
    LDX #.vduGraphicsCursorPixelsXLow    - .vduVariablesStart   source (centre of circle)
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   destination (old graphics
                                                                point)
    JSR .copyFourBytesWithinVDUVariables                        copy current graphics cursor
                                                                position to old graphics
                                                                cursor position
                                                                i.e. copy the centre of the
                                                                circle

    Get radius squared
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   centre of circle
    LDX #.vdu25ParameterXLow             - .vduVariablesStart   plot position
    JSR .getCircleRadiusSquared                                 

    Initialise circle variables
    JSR .circleInitialisation                                   

    Loop to draw the circle
    Each time around the loop we move to the next pixel around the first quadrant
    of the circle and we reflect to draw the other quadrants
.circleOutlineLoop = $9055
    Add the centre point to get the right hand side point on the circle, then reflect
    about the centre Y axis to get the left side point on the circle.
    
    i.e.:
      .circlePointRight = (centreX + pointX, centreY + pointY)
      .circlePointLeft  = (centreX - pointX, centreY + pointY)
    JSR .reflectCirclePointXAboutCircleCentre           Set X coordinates
    JSR .addCirclePointYToCircleCentre                  Set Y coordinates

    Plot four points symmetrically about the centre of the circle

    Plot right point (quadrant 0)
    LDX #.circlePointRightXLow - .vduVariablesStart     
    JSR .plotPointXInternal                             plot point .circlePointRight

    Don't draw the left point if exactly on the horizontal centre line
    (since it would be the same as the right point already drawn)
    LDA .circlePointXLow                                
    ORA .circlePointXHigh                               
    BEQ +                                               if (circle X is zero) then branch
                                                        (skip forward)

    Plot left point (quadrant 1)
    LDX #.circlePointLeftXLow - .vduVariablesStart      
    JSR .plotPointXInternal                             plot point .circlePointLeft

+
    Don't reflect below the centre row if exactly on the centre row
    LDA .circlePointYLow                                
    ORA .circlePointYHigh                               
    BEQ .circleOutlineNext                              if (circle point Y is zero) then
                                                        branch (skip forward)

    JSR .reflectPointVerticallyAboutCircleCentre        reflect points .circlePointLeft and
                                                        .circlePointRight
                                                        vertically about the centre

    Plot right point (quadrant 3)
    LDX #.circlePointRightXLow - .vduVariablesStart     
    JSR .plotPointXInternal                             plot point .circlePointRight

    Don't reflect if on the horizontal centre line
    LDA .circlePointXLow                                
    ORA .circlePointXHigh                               
    BEQ .circleOutlineNext                              if (circle X is zero) then branch
                                                        (skip forward)

    Plot left point (quadrant 2)
    LDX #.circlePointLeftXLow - .vduVariablesStart      
    JSR .plotPointXInternal                             plot point .circlePointLeft

.circleOutlineNext = $908a
    JSR .circleIncrement                                move to next pixel
    LDA .circlePointXHigh                               
    BPL .circleOutlineLoop                              if (circle point X >= 0) then branch
                                                        (loop back)

    JMP .setGraphicsCursorPositionAndFinishPLOT         

§3. Plot a filled circle.

 The circle is specified by two points, the centre point and a point on the radius.

 On Entry:
   .vduGraphicsCursorPixelsXLow: centre point [4 bytes]
   .vdu25ParameterXLow: point on radius [4 bytes]
.plotCircleFilled = $9095
    Copy centre of circle to old graphics cursor position
    LDX #.vduGraphicsCursorPixelsXLow - .vduVariablesStart      source
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   destination
    JSR .copyFourBytesWithinVDUVariables                        

    Get radius squared
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart 
    LDX #.vdu25ParameterXLow - .vduVariablesStart       
    JSR .getCircleRadiusSquared                         

    Initialise circle variables
    JSR .circleInitialisation                           

    Loop to draw the circle
    Each time around the loop we move to the next row of the circle moving from the
    centre row upwards to the top, reflecting each time to draw the rows below the
    centre.
.circleFilledLoop = $90a6
    Add the centre point to get the right hand side point on the circle, then reflect
    about the centre Y axis to get the left side point on the circle.
    
    i.e.:
      .circlePointRight = (centreX + pointX, centreY + pointY)
      .circlePointLeft  = (centreX - pointX, centreY + pointY)
    JSR .reflectCirclePointXAboutCircleCentre           Set X coordinates
    JSR .addCirclePointYToCircleCentre                  Set Y coordinates

    draw row in upper half of circle
    LDY #.circlePointRightXLow - .vduVariablesStart     
    LDX #.circlePointLeftXLow - .vduVariablesStart      
    JSR .setMasksAndFillRow                             

    if we are on the centre row, skip forward
    LDA .circlePointYLow                                
    ORA .circlePointYHigh                               
    BEQ +                                               

    Reflect points below the centre
    JSR .reflectPointVerticallyAboutCircleCentre        reflect points vertically about the
                                                        centre
                                                        this gives us the points in the
                                                        remaining two quadrants

    draw row in lower half of circle
    LDY #.circlePointRightXLow - .vduVariablesStart     
    LDX #.circlePointLeftXLow - .vduVariablesStart      
    JSR .setMasksAndFillRow                             

+
    Increment the circle point until we reach a new row, then loop back to .circleFilledLoop
    LDA #0                                              
    STA .circleFillRowFlag                              flag to tell us when we reach a new
                                                        row
.circleRowLoop = $90ca
    JSR .circleIncrement                                move to next pixel around circle

    LDA .circlePointXHigh                               }
    BMI .finishedCircleFilled                           } if (finished) then branch

    LDA .circleFillRowFlag                              }
    BEQ .circleRowLoop                                  } if (not on new row yet) loop back
    BNE .circleFilledLoop                               ALWAYS branch (loop back)

.finishedCircleFilled = $90d9
    JMP .setGraphicsCursorPositionAndFinishPLOT         

§4. Get the circle radius squared.

 By calculating deltaX^2 + deltaY^2 we get the radius squared.

 On Entry:
   X: the vdu variables offset to the centre point of the circle
   Y: the vdu variables offset to a point on the circumference of the circle

 On Exit:
   .circleRadiusSquared and .gxrTemp4567: radius squared, i.e.: (deltaX^2) + (deltaY^2)
.getCircleRadiusSquared = $90dc
    STX .vduTempStoreDE                                 remember initial X
    STY .vduTempStoreDF                                 remember initial Y

    .gxrTemp12 = delta X
    SEC                                                 }
    LDA .vduVariablesStart,X                            }
    SBC .vduVariablesStart,Y                            }
    STA .gxrTemp1                                       } .gxrTemp12 = point[X].X -
                                                        } point[Y].X
    LDA .vduVariablesStart + 1,X                        }            = width (signed value)
    SBC .vduVariablesStart + 1,Y                        }
    STA .gxrTemp2                                       }

    Compensate for double width pixels (MODE 2,5)
    LDX .vduCurrentScreenMODE                           
    LDA .pixelShapeForMODE,X                            
    STA .circlePixelShapeForCurrentMODE                 store pixel shape based on MODE
    AND #1                                              
    BEQ +                                               if (not double width pixels) then
                                                        branch

    to handle double width pixels (MODE 2,5), we double delta X, and deal with the
    consequences
    in the update routine (see .circleIncrement)
    ASL .gxrTemp1                                       }
    ROL .gxrTemp2                                       } multiply X coordinate by two to
                                                        } compensate
+

    Square delta X
    JSR .square12_into4567                              square width in .gxrTemp12 to
                                                        .gxrTemp4567

    .circleRadiusSquared = .gxrTemp4567
    LDX #3                                              loop counter
-
    LDA .gxrTemp4,X                                     
    STA .circleRadiusSquaredLow,X                       
    DEX                                                 
    BPL -                                               

    LDX .vduTempStoreDE                                 } recall initial X, Y variables
    LDY .vduTempStoreDF                                 }


    .gxrTemp12 = delta Y
    SEC                                                 }
    LDA .vduVariablesStart + 2,X                        }
    SBC .vduVariablesStart + 2,Y                        }
    STA .gxrTemp1                                       } .gxrTemp12 = point[X].Y -
                                                        } point[Y].Y
    LDA .vduVariablesStart + 3,X                        }            = height (signed value)
    SBC .vduVariablesStart + 3,Y                        }
    STA .gxrTemp2                                       }

    Compensate for half width pixels (MODE 0)
    LDA .circlePixelShapeForCurrentMODE                 get pixel shape based on MODE
    AND #2                                              
    BEQ +                                               if (not half width pixels) then
                                                        branch

    to handle half width pixels (MODE 0), we double the delta Y, and deal with the
    consequences
    in the update routine (see .circleIncrement)
    ASL .gxrTemp1                                       }
    ROL .gxrTemp2                                       } multiply Y coordinate by two to
                                                        } compensate
+

    Square delta Y
    JSR .square12_into4567                              square height in .gxrTemp12 into
                                                        .gxrTemp4567

    .circleRadiusSquaredLow += .gxrTemp4567
    i.e. .circleRadiusSquaredLow = (deltaX^2) + (deltaY^2)
    .sqrtNumber0 = .circleRadiusSquaredLow
    CLC                                               
    LDX #$FC                                          loop counter ($FC,$FD,$FE,$FF)
-
    LDA .circleRadiusSquaredLow - $FC,X               .circleRadiusSquared += .gxrTemp4567
    ADC .sqrtNumber0 - $FC,X                          
    STA .circleRadiusSquaredLow - $FC,X               
    STA .sqrtNumber0 - $FC,X                          .sqrtNumber0123 = .circleRadiusSquared
    INX                                               increment loop counter
    BMI -                                             if (not done) then branch (loop back)
    RTS                                               

§5. Initialise circle plotting variables.

 Gets the initial point on the circle (along the positive X-axis, quadrant 0), and initialises
 other variables to help in moving from point to point around the circle.

 Given the square of the radius 'square_r', we take the integer square root to get an integer
 value for the radius: floor_r = floor(sqrtf(square_r)).

 Because the square root function rounds down using the floor function, we ideally want to get
 closer to a proper rounded value: round(sqrtf(square_r)).

   i.e. we want something closer to:

       float float_r = sqrtf(square_r)
       float f = float_r+0.5
       int ideal_radius = floor(f)

 We first calculate the regular integer square root to get floor_r = floor(sqrtf(square_r)), but
 then want to get closer to f.

 Note that f = (float_r+0.5) and:

   f^2 = (float_r+0.5)^2 = float_r^2 + float_r + 0.25

 We already know square_r = float_r^2. We approximate floor_r ~= (float_r + 0.25)
 So we calculate 'square_r + floor_r' and then take the integer square root, to get
 a closer approximation to the ideal_radius = floor(f).

 One of the other variables is the decision variable (.circleDecision). This tracks how
 close we are to the ideal circle radius by tracking the difference between our desired
 radius squared and the current radius squared.

 On Entry:
   .circleRadiusSquared:  radius squared [4 bytes]
   .sqrtNumber0123:       radius squared [4 bytes]
 On Exit:
   .circlePointX: radius   } initial point on circle along X axis = (radius,0)
   .circlePointY: 0        }
   .circleDiameterCountdown: diameter-1    (counts down in steps of 2)
   .circleCountOddNumbers: 1               (counts up in steps of 2)
   .circlePixelShapeCurrentOffset: 3       (accounting for pixel shape)
   .circleDecision: desired radius squared - current radius squared
.circleInitialisation = $914e
    radius = sqrt(radius squared)
    JSR .sqrt32                                         .gxrTemp12 = sqrt(.gxrTemp4567)

    .circleRadiusSquared  += .gxrTemp12 (i.e. .circleRadiusSquaredLow = radius^2 + radius)
    .sqrtNumber0123 = .circleRadiusSquared
    CLC                                                 }
    LDA .gxrTemp1                                       }
    ADC .circleRadiusSquaredLow                         }
    STA .circleRadiusSquaredLow                         }
    STA .sqrtNumber0                                    }
    LDA .gxrTemp2                                       } .circleRadiusSquared +=.gxrTemp12
    ADC .circleRadiusSquaredMid1                        }
    STA .circleRadiusSquaredMid1                        } .sqrtNumber0123 =
                                                        } .circleRadiusSquared
    STA .sqrtNumber1                                    }
    LDA #0                                              }
    ADC .circleRadiusSquaredMid2                        }
    STA .circleRadiusSquaredMid2                        }
    STA .sqrtNumber2                                    }
    LDA #0                                              }
    ADC .circleRadiusSquaredHigh                        }
    STA .circleRadiusSquaredHigh                        }
    STA .sqrtNumber3                                    }

    .sqrtResult01 = sqrt(.sqrtNumber0123) i.e. sqrt(radius^2 + radius)
    JSR .sqrt32                                         .gxrTemp12 = sqrt(.gxrTemp4567)

    .circlePointX = .sqrtResult01
    .circleDiameterCountdown = 2*.circlePointX - 1
    LDA .sqrtResult0                                    }
    STA .circlePointXLow                                } .circlePointX = .sqrtResult0
    ASL                                                 }
    STA .circleDiameterCountdownLow                     } .circleDiameterCountdown = twice X
                                                        } point
    LDA .sqrtResult1                                    }
    STA .circlePointXHigh                               }
    ROL                                                 }
    STA .circleDiameterCountdownHigh                    }

    LDA .circleDiameterCountdownLow                     }
    BNE +                                               } .circleDiameterCountdown--
    DEC .circleDiameterCountdownHigh                    }
+                                                       }
    DEC .circleDiameterCountdownLow                     }

    Now we have our actual radius we are going to draw, we square it to get the actual
    radius squared
    JSR .square12_into4567                              .gxrTemp4567 = .sqrtResult01 *
                                                        .sqrtResult01

    .circleDecision = .circleRadiusSquared - .gxrTemp45 = (radius^2 + radius) - (actual
    radius)^2
    SEC                                                 }
    LDA .circleRadiusSquaredLow                         }
    SBC .gxrTemp4                                       }
    STA .circleDecisionLow                              } .circleDecision =
                                                        } .circleRadiusSquared - .gxrTemp45
    LDA .circleRadiusSquaredMid1                        }
    SBC .gxrTemp5                                       }
    STA .circleDecisionHigh                             }

    .circlePointY = 0
    LDA #0                                              
    STA .circlePointYHigh                               
    STA .circlePointYLow                                

    .circleCountOddNumbers = 1
    STA .circleCountOddNumbersHigh                      
    LDA #1                                              
    STA .circleCountOddNumbersLow                       

    .circlePixelShapeCurrentOffset = 3
    LDA #3                                              
    STA .circlePixelShapeCurrentOffset                  

    Scale X based on pixel shape
    LDA .circlePixelShapeForCurrentMODE                 get pixel shape based on MODE
    AND #1                                              
    BEQ +                                               if (not double width) then branch

    LSR .circlePointXHigh                               divide width by two
    ROR .circlePointXLow                                
+
    RTS                                                 

§6. Moves coordinates onto the next pixel around the circle.

 Update the point 'circlePoint' to be the next pixel around the circle anticlockwise from the
 positive x-axis (in quadrant 0). Uses something akin to Bresenham's Circle Algorithm.

 circlePixelShapeCurrentOffset = pixel shape for current MODE
 repeat:
     if circleDecision < circleCountOddNumbers:
         circleDecision += circleDiameterCountdown
         circleDiameterCountdown -= 2
         circlePixelShapeCurrentOffset = circlePixelShapeCurrentOffset EOR 1
         if (circlePixelShapeCurrentOffset AND 1) { circlePointX-- }
         if (circleDecision < circleCountOddNumbers) then goto "circle_continues"

     circleDecision -= circleCountOddNumbers
     circleCountOddNumbers += 2
     circlePixelShapeCurrentOffset = circlePixelShapeCurrentOffset EOR 2
     if circlePixelShapeCurrentOffset AND 2:
         circleFillRowFlag = 1               (start of new row)
         circlePointY++
     "circle_continues"
 until (circlePixelShapeCurrentOffset != 0)
.circleIncrement = $91db
    The shape of pixels can be double width or half width (compared to MODE 1)
    LDA .circlePixelShapeCurrentOffset                  } .circlePixelShapeCurrentOffset &=
    AND .circlePixelShapeForCurrentMODE                 } pixel shape based on MODE
    STA .circlePixelShapeCurrentOffset                  }

.circleIncrementInternal = $91e4
    SEC                                                 }
    LDA .circleDecisionLow                              }
    SBC .circleCountOddNumbersLow                       } X = .circleDecision -
    TAX                                                 }     .circleCountOddNumbersLow

    LDA .circleDecisionHigh                             
    SBC .circleCountOddNumbersHigh                      
    BPL .incrementY                                     if (.circleDecision >=
                                                        .circleCountOddNumbers) then branch

    CLC                                                 }
    LDA .circleDecisionLow                              }
    ADC .circleDiameterCountdownLow                     }
    STA .circleDecisionLow                              } .circleDecision +=
    LDA .circleDecisionHigh                             }      .circleDiameterCountdown
    ADC .circleDiameterCountdownHigh                    }
    STA .circleDecisionHigh                             }

    SEC                                                 }
    LDA .circleDiameterCountdownLow                     }
    SBC #2                                              }
    STA .circleDiameterCountdownLow                     } .circleDiameterCountdown -= 2
    BCS +                                               }
    DEC .circleDiameterCountdownHigh                    }
+

    Account for double width pixel shape
    
    In double width pixel modes (MODE 2, 5) we skip decrementing X every other time to
    account for the fact we doubled the deltaX coordinate in the setup routine (see
    .getCircleRadiusSquared)
    LDA .circlePixelShapeCurrentOffset                  }
    EOR #1                                              } .circlePixelShapeCurrentOffset ^= 1
    STA .circlePixelShapeCurrentOffset                  }
    AND #1                                              
    BEQ .skipMoveLeft                                   

    LDA .circlePointXLow                                }
    BNE +                                               }
    DEC .circlePointXHigh                               } .circlePointX--
+                                                       }
    DEC .circlePointXLow                                }

.skipMoveLeft = $922c
    SEC                                                 }
    LDA .circleDecisionLow                              }
    SBC .circleCountOddNumbersLow                       } X = .circleDecisionLow -
    TAX                                                 }      .circleCountOddNumbersLow

    LDA .circleDecisionHigh                             }
    SBC .circleCountOddNumbersHigh                      }
    BMI .circleContinues                                } if (.circleDecision <
                                                        } .circleCountOddNumbers) then branch

.incrementY = $923c
    STA .circleDecisionHigh                             } Finish subtraction started earlier:
    STX .circleDecisionLow                              } .circleDecision -=
                                                        } .circleCountOddNumbers

    CLC                                                 }
    LDA .circleCountOddNumbersLow                       }
    ADC #2                                              } .circleCountOddNumbers += 2
    STA .circleCountOddNumbersLow                       }
    BCC +                                               }
    INC .circleCountOddNumbersHigh                      }
+

    Account for half width pixel shape
    
    In half width pixel MODEs (MODE 0) we skip incrementing Y every other time to
    account for the fact we doubled the deltaY coordinate in the setup routine (see
    .getCircleRadiusSquared)
    LDA .circlePixelShapeCurrentOffset                  }
    EOR #2                                              } .circlePixelShapeCurrentOffset ^= 2
    STA .circlePixelShapeCurrentOffset                  }
    AND #2                                              
    BEQ .circleContinues                                if (bit 2 clear) then branch

    INC .circleFillRowFlag                              set the circle fill flag (moving to
                                                        a new row)

    INC .circlePointYLow                                }
    BNE .circleContinues                                }
    INC .circlePointYHigh                               } .circlePointY++

.circleContinues = $9267
    If the pixel shape for the current mode requires we do a second loop then loop back,
    otherwise finish
    LDA .circlePixelShapeCurrentOffset                  
    BNE .return10                                       if (done) then branch (return)
    JMP .circleIncrementInternal                        loop back

.return10 = $926f
    RTS                                                 

§7. Plot an arc of a circle.

                                        KEY: # = chord
                             circle          * = arc
 point defining                |             / = start line
 end of arc ---->\            \|/            \ = end line
 (PLOT parameter) \         ******
                   \    ****      ****
  leftmost end of-> \#######          ***
            chord    \      ########     **
                      \             ######## <---- start of arc (current graphics cursor pos)
                       \                 _/        = rightmost end of chord
                        \               /
                         \            _/
                 end line \          / start line
                           \       _/
                            \     /
                             \  _/
                              \/ <---- centre of circle (old graphics cursor pos)
.plotCircleArc = $9270
    LDA #0                                              }
    STA .circleChordLine                                } no chord line to track for an arc
    JSR .circleDoLineAndQuadrantInitialisation          

    Get radius squared
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   circle centre
    LDX #.vduGraphicsCursorPixelsXLow - .vduVariablesStart      start point
    JSR .getCircleRadiusSquared                                 

    Initialise circle variables
    JSR .circleInitialisation                                   

.plotCircleArcLoop = $9282
    Each time around this loop is the next pixel around the circle.
    
    We start with the point on the circle to the right on the horizontal centre line
    and work up anticlockwise, plotting until we reach the top of the quadrant. We reflect
    as we go to generate the same points in the remaining quadrants.

    Add the centre point to get the right hand side point on the circle, then reflect
    about the centre Y axis to get the left side point on the circle.
    
    i.e.:
      .circlePointRight = (centreX + pointX, centreY + pointY)
      .circlePointLeft  = (centreX - pointX, centreY + pointY)
    JSR .reflectCirclePointXAboutCircleCentre           Set X coordinates
    JSR .addCirclePointYToCircleCentre                  Set Y coordinates

    Prepare data for quadrant zero (top right quadrant)
    LDY #0                                              
    JSR .circlePrepareForRightSideQuadrant              

    Prepare data for quadrant one (top left quadrant)
    LDY #1                                              
    JSR .circlePrepareForLeftSideQuadrant               

    Are we the correct side of the chord line?
    LDX .circleTrackingRightmostChordPoint              
    CPX #.circlePointRightXLow - .vduVariablesStart     
    BNE +                                               if (not the correct side of the
                                                        chord) then branch

    Plot right side point (quadrant 0)
    JSR .plotPointXInternal                             plot point .circlePointRight

+
    if (on the centre column) then branch (we can't reflect left of the centre, skip forward)
    LDA .circlePointXLow                                
    ORA .circlePointXHigh                               
    BEQ +                                               if (X coordinate is zero) then branch

    Are we the correct side of the chord line?
    LDX .circleTrackingLeftmostChordPoint               
    CPX #.circlePointLeftXLow - .vduVariablesStart      
    BNE +                                               if (not the correct side of the
                                                        chord) then branch

    Plot left side point (quadrant 1)
    JSR .plotPointXInternal                             plot point .circlePointLeft

+
    if (on the centre row) then branch (we can't reflect below the line, skip forward)
    LDA .circlePointYLow                                
    ORA .circlePointYHigh                               
    BEQ .nextCirclePoint                                if (Y coordinate is zero) then branch

    
    Draw below the centre row
    
    JSR .reflectPointVerticallyAboutCircleCentre        reflect points .circlePointLeft,
                                                        .circlePointRight vertically below
                                                        the centre row

    Prepare data for quadrant three (bottom right quadrant)
    LDY #3                                              
    JSR .circlePrepareForRightSideQuadrant              

    Prepare data for quadrant two (bottom left quadrant)
    LDY #2                                              
    JSR .circlePrepareForLeftSideQuadrant               

    Are we the correct side of the chord line?
    LDX .circleTrackingRightmostChordPoint              
    CPX #.circlePointRightXLow - .vduVariablesStart     
    BNE +                                               if (not the correct side of chord
                                                        line) then branch

    Plot right point (quadrant 2)
    JSR .plotPointXInternal                             plot right point

+
    if (on centre column) then branch (we can't reflect left of the line, skip forward)
    LDA .circlePointXLow                                
    ORA .circlePointXHigh                               
    BEQ .nextCirclePoint                                if (X coordinate on centre column)
                                                        then branch

    Are we the correct side of the chord line?
    LDX .circleTrackingLeftmostChordPoint               
    CPX #.circlePointLeftXLow - .vduVariablesStart      
    BNE .nextCirclePoint                                if (not the correct side of the
                                                        chord) then branch

    Plot left point (quadrant 3)
    JSR .plotPointXInternal                             plot left point

.nextCirclePoint = $92df
    JSR .circleIncrement                                move to next point

    LDA .circlePointXHigh                               
    BPL .plotCircleArcLoop                              loop back if not done

    JMP .setGraphicsCursorPositionAndFinishPLOT         finally move graphics cursor

§8. Plot a sector of a circle.

                                        KEY: * = sector
                                             / = start line
                                             \ = end line
 end of arc ----> \         ******
 (PLOT parameter)  \    **************
                    \********************
                     \*********************
                      \********************* <---- start of arc (graphics cursor)
                       \******************/
                        \***************/
                         \*************/
                 end line \**********/ start line
                           \********/
                            \*****/
                             \***/
                              \/ <---- centre of circle (old graphics cursor)
.plotCircleSector = $92ea
    LDA #0                                                      
    STA .circleChordLine                                        no chord line to track
    LDA #1                                                      
    STA .circleFillRowFlag                                      set flag to indicate we have
                                                                just incremented our circle
                                                                point to a new row
    JSR .circleDoLineAndQuadrantInitialisation                  

    Get radius squared
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   
    LDX #.vduGraphicsCursorPixelsXLow - .vduVariablesStart      
    JSR .getCircleRadiusSquared                                 

    Initialise circle variables
    JSR .circleInitialisation                                   

.plotCircleSectorLoop = $9301
    Each time around this loop is the next pixel around the circle. This may or may
    not be on a new row. The flag '.circleFillRowFlag' is set when we should draw the
    next row.
    We start with the point on the circle to the right on the horizontal centre line
    and work up anticlockwise, plotting rows until we reach the top of the quadrant.
    We reflect about the centre point to generate the same rows moving downwards from
    the centre line too.

    Add the centre point to get the right hand side point on the circle, then reflect
    about the centre Y axis to get the left side point on the circle.
    
    i.e.:
      .circlePointRight = (centreX + pointX, centreY + pointY)
      .circlePointLeft  = (centreX - pointX, centreY + pointY)
    JSR .reflectCirclePointXAboutCircleCentre           Set X coordinates
    JSR .addCirclePointYToCircleCentre                  Set Y coordinates

    Prepare data for quadrant zero (top right quadrant)
    LDY #0                                              
    JSR .circlePrepareForRightSideQuadrant              

    Prepare data for quadrant one (top left quadrant)
    LDY #1                                              
    JSR .circlePrepareForLeftSideQuadrant               

    If not plotting this time around the loop (just updating), then branch
    LDA .circleFillRowFlag                              
    BEQ .plotRowInLowerHalf                             

    Check if on centre row
    LDA .circlePointYLow                                
    ORA .circlePointYHigh                               
    BNE .notOnCentreRow                                 if (not on centre row) then branch

    We are on the centre row
    Check if we have something to plot in this quadrant
    LDA .circleTrackingRightmostChordPoint              
    BNE .somethingInQuadrant                            if (something to plot in this
                                                        quadrant) then branch

    Nothing to plot in quadrant

    Push the appropriate values for use in the lower half
    LDA .circleTrackingSecondLineInQuadrant             }
    PHA                                                 } push second line;
    LDA .circleTrackingLeftmostChordPoint               }
    PHA                                                 } push leftmost chord point;
    JMP .plotRowInLowerHalf                             


.somethingInQuadrant = $932e
    Push the appropriate values for use in the lower half
    PHA                                                 push rightmost chord point;
    LDA .circleTrackingLeftmostChordPoint               }
    BNE .pushAAndReflectBelowCentre                     } if (leftmost chord point == 0)
                                                        } then push radial line; else push
                                                        } leftmost chord point;
    LDA .circleRadialLine                               }
.pushAAndReflectBelowCentre = $9337
    PHA                                                 }
    JMP .plotRowInLowerHalf                             

.notOnCentreRow = $933b
    LDY .circleTrackingRightmostChordPoint              
    BEQ .nothingToPlot                                  if (nothing to plot in this
                                                        quadrant) then branch

    LDX .circleRadialLine                               
    BEQ .nothingToPlot2                                 

    JSR .setMasksAndFillRow                             fill row

.nothingToPlot = $9348
    LDY .circleTrackingSecondLineInQuadrant             
.nothingToPlot2 = $934b
    LDX .circleTrackingLeftmostChordPoint               
    BEQ .plotRowInLowerHalf                             

    JSR .setMasksAndFillRow                             


.plotRowInLowerHalf = $9353
    
    Now draw the bottom half (i.e. the bottom two quadrants)
    
    JSR .reflectPointVerticallyAboutCircleCentre        reflect points vertically about the
                                                        centre row

    Prepare data for quadrant 3 (bottom right quadrant)
    LDY #3                                              
    JSR .circlePrepareForRightSideQuadrant              

    Prepare data for quadrant 2 (bottom left quadrant)
    LDY #2                                              
    JSR .circlePrepareForLeftSideQuadrant               

    LDA .circleFillRowFlag                              
    BEQ .nextCircleSectorPoint                          if (not plotting this time around
                                                        the loop, just updating) then branch

    Check if on Y=0 centre row
    LDA .circlePointYLow                                
    ORA .circlePointYHigh                               
    BNE .notOnCentreRow2                                

    
    On centre row. Adjust values for centre row
    
    PLA                                                 
    TAY                                                 
    LDA .circleTrackingRightmostChordPoint              
    BNE .lNotZero                                       

    LDA .circleTrackingSecondLineInQuadrant             
    PHA                                                 
    LDX .circleTrackingLeftmostChordPoint               
    JMP .branch1                                        

.lNotZero = $937e
    PHA                                                 
    LDX .circleTrackingLeftmostChordPoint               
    BNE .branch1                                        [NOTE: Could do BNE .testY instead]

    LDX .circleRadialLine                               
.branch1 = $9387
    BNE .testY                                          
    STY .circleTrackingLeftmostChordPoint               
    JMP .pullValuesAndTest                              

.testY = $938f
    CPY #0                                              
    BNE .sortValues                                     if (Y != 0) then branch (sort values)

    STX .circleTrackingLeftmostChordPoint               
    JMP .pullValuesAndTest                              

.sortValues = $9399
    JSR .gxrSortPointsXY                                
    STX .circleTrackingLeftmostChordPoint               

.pullValuesAndTest = $939f
    PLA                                                 }
    TAX                                                 } X = pull
    PLA                                                 } Y = pull
    TAY                                                 }
    BNE .testX                                          if (Y != 0) then branch

    TXA                                                 
    TAY                                                 Y=X
    JMP .setLineAndPlot                                 

.testX = $93aa
    CPX #0                                              
    BEQ .setLineAndPlot                                 if (X == 0) then branch (don't sort
                                                        vertices)

    JSR .gxrSortPointsXY                                

.setLineAndPlot = $93b1
    LDX .circleTrackingLeftmostChordPoint               
    JMP .plotRow                                        plot row


.notOnCentreRow2 = $93b7
    LDY .circleTrackingRightmostChordPoint              
    BEQ .nothingToPlot3                                 if (nothing to plot in this
                                                        quadrant) then branch

    LDX .circleRadialLine                               
    BEQ .nothingToPlot4                                 

    JSR .setMasksAndFillRow                             plot row

.nothingToPlot3 = $93c4
    LDY .circleTrackingSecondLineInQuadrant             
.nothingToPlot4 = $93c7
    LDX .circleTrackingLeftmostChordPoint               
    BEQ .nextCircleSectorPoint                          if (nothing to plot) then branch

.plotRow = $93cc
    JSR .setMasksAndFillRow                             plot row

.nextCircleSectorPoint = $93cf
    LDA #0                                              
    STA .circleFillRowFlag                              clear flag, no longer on a new row
    JSR .circleIncrement                                

    LDA .circlePointXHigh                               
    BMI +                                               if (X coordinate is negative) then
                                                        branch (finished drawing)
    JMP .plotCircleSectorLoop                           jump back to continue drawing
+
    JMP .setGraphicsCursorPositionAndFinishPLOT         

§9. Plot a segment of a circle.

                                        KEY: # = chord
                             circle          * = segment ('#' is also part of segment)
 point defining                |             / = start line
 end of arc ---->\            \|/            \ = end line
 (PLOT parameter) \         ******
                   \    **************
  leftmost end of-> \#######*************
            chord    \      ########*******
                      \             ######## <---- start of arc (current graphics cursor pos)
                       \                 _/        = rightmost end of chord
                        \               /
                         \            _/
                 end line \          / start line
                           \       _/
                            \     /
                             \  _/
                              \/ <---- centre of circle (old graphics cursor pos)
.plotCircleSegment = $93e2
    LDA #0                                              
    STA .circleChordLine                                no chord line to track, yet
    LDA #1                                              } set, as if we have just incremented
    STA .circleFillRowFlag                              } our circle point to a new row
    JSR .circleDoLineAndQuadrantInitialisation          

    Get radius squared
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   
    LDX #.vduGraphicsCursorPixelsXLow - .vduVariablesStart      
    JSR .getCircleRadiusSquared                         

    Initialise circle variables
    JSR .circleInitialisation                           
    JSR .segmentInitialisation                          

.plotUpperHalfOfCircleSegmentLoop = $93fc
    Each time around this loop is the next pixel around the circle. This may or may
    not be on a new row. The flag 'circleFillRowFlag' is set when we should draw the
    next row.
    We start with the point on the circle to the right on the horizontal centre line
    and work up anticlockwise, plotting rows until we reach the top of the quadrant.
    We reflect about the centre point to generate the same rows moving downwards from
    the centre line too.

    Add the centre point to get the right hand side point on the circle, then reflect
    about the centre Y axis to get the left side point on the circle.
    
    i.e.:
      .circlePointRight = (centreX + pointX, centreY + pointY)
      .circlePointLeft  = (centreX - pointX, centreY + pointY)
    JSR .reflectCirclePointXAboutCircleCentre           Set X coordinates
    JSR .addCirclePointYToCircleCentre                  Set Y coordinates

    Prepare data for quadrant zero (top right quadrant)
    LDY #0                                              
    JSR .circlePrepareForRightSideQuadrant              

    Prepare data for quadrant one (top left quadrant)
    LDY #1                                              
    JSR .circlePrepareForLeftSideQuadrant               

    LDY .circleTrackingRightmostChordPoint              
    CPY #.circlePointRightXLow - .vduVariablesStart     
    BNE .notTrackingChord1                              if (not the correct side of the
                                                        rightmost end of the chord
                                                        vertically) then branch

    LDX .circleTrackingLeftmostChordPoint               
    CPX #.circlePointLeftXLow - .vduVariablesStart      
    BEQ .notTrackingChord2                              if (not the correct side of the
                                                        leftmost end of the chord
                                                        vertically) then branch

    We are vertically in between the two ends of the chord
    JSR .advanceAlongChordLineUntilNewRow               move along the chord line

    LDY #.circlePointRightXLow - .vduVariablesStart     
    LDX .circleChordLine                                chord line to track

.notTrackingChord2 = $9422
    LDA .circleFillRowFlag                              
    BEQ .moveToNextCirclePoint                          if (not plotting this time around
                                                        the loop, just updating) then branch

    JSR .setMasksAndFillRow                             fill row
    JMP .moveToNextCirclePoint                          

.notTrackingChord1 = $942d
    LDX .circleTrackingLeftmostChordPoint               
    CPX #.circlePointLeftXLow - .vduVariablesStart      
    BNE .moveToNextCirclePoint                          if (not the correct side of the
                                                        leftmost end of the chord
                                                        vertically) then branch

    Move along the chord line horizontally
    JSR .advanceAlongChordLineUntilNewRow               

    LDX #.circlePointLeftXLow - .vduVariablesStart      
    LDY .circleChordLine                                chord line to track
    LDA .circleFillRowFlag                              
    BEQ .moveToNextCirclePoint                          if (not plotting this time around
                                                        the loop, just updating) then branch

    JSR .setMasksAndFillRow                             fill row

.moveToNextCirclePoint = $9444
    LDA #0                                              
    STA .circleFillRowFlag                              zero flag
    JSR .circleIncrement                                move to next pixel around the circle

    LDA .circlePointXHigh                               
    BPL .plotUpperHalfOfCircleSegmentLoop               if (X coordinate is still positive)
                                                        then branch (loop back)

    
    Now draw the bottom half (i.e. the bottom two quadrants)
    

    Get radius squared
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   centre of circle
    LDX #.vduGraphicsCursorPixelsXLow - .vduVariablesStart      start arc point
    JSR .getCircleRadiusSquared                                 

    Initialise circle variables
    JSR .circleInitialisation                           

    LDA #0                                              }
    STA .circleChordLine                                } no chord line to track, yet
    JSR .segmentInitialisationIfStraddlingTheCentreRow  

    If (on centre row already) then zero the fill flag
    LDA .circlePointYLow                                
    ORA .circlePointYHigh                               
    BNE .plotLowerHalfOfCircleSegmentLoop               if (not on Y=0 centre row) then
                                                        branch
    STA .circleFillRowFlag                              zero flag

.plotLowerHalfOfCircleSegmentLoop = $946e
    Add the centre point to get the right hand side point on the circle, then reflect
    about the centre Y axis to get the left side point on the circle.
    Reflect below the centre row.
    
    i.e.:
      .circlePointRight = (centreX + pointX, centreY - pointY)
      .circlePointLeft  = (centreX - pointX, centreY - pointY)
    JSR .reflectCirclePointXAboutCircleCentre           Set X coordinates
    JSR .reflectPointVerticallyAboutCircleCentre        reflect points vertically about the
                                                        centre

    Prepare data for quadrant three
    LDY #3                                              
    JSR .circlePrepareForRightSideQuadrant              

    Prepare data for quadrant two
    LDY #2                                              
    JSR .circlePrepareForLeftSideQuadrant               


    We check to see if we are currently between the top and bottom of the chord line.
    If so then we are tracking the chord line.
    LDY .circleTrackingRightmostChordPoint              
    CPY #.circlePointRightXLow - .vduVariablesStart     
    BNE .notTrackingChord3                              if (not the correct side of the
                                                        rightmost end of the chord
                                                        vertically) then branch

    LDX .circleTrackingLeftmostChordPoint               
    CPX #.circlePointLeftXLow - .vduVariablesStart      
    BEQ .notTrackingChord4                              if (not the correct side of the
                                                        leftmost end of the chord
                                                        vertically) then branch

    Move along the chord line horizontally
    JSR .advanceAlongChordLineUntilNewRow               

    LDY #.circlePointRightXLow - .vduVariablesStart     
    LDX .circleChordLine                                chord line to track
.notTrackingChord4 = $9494
    LDA .circleFillRowFlag                              
    BEQ .moveToNextCirclePoint2                         if (not on new row) then branch

    JSR .setMasksAndFillRow                             
    JMP .moveToNextCirclePoint2                         

.notTrackingChord3 = $949f
    LDX .circleTrackingLeftmostChordPoint               
    CPX #.circlePointLeftXLow - .vduVariablesStart      
    BNE .moveToNextCirclePoint2                         if (not the correct side of the
                                                        leftmost end of the chord
                                                        vertically) then branch

    Move along the chord line horizontally
    JSR .advanceAlongChordLineUntilNewRow               

    LDX #.circlePointLeftXLow - .vduVariablesStart      
    LDY .circleChordLine                                chord line to track
    LDA .circleFillRowFlag                              
    BEQ .moveToNextCirclePoint2                         if (not plotting this time around
                                                        the loop, just updating) then branch

    JSR .setMasksAndFillRow                             

.moveToNextCirclePoint2 = $94b6
    LDA #0                                              
    STA .circleFillRowFlag                              zero flag, no longer on a new row
    JSR .circleIncrement                                move to next point on circle

    LDA .circlePointXHigh                               
    BPL .plotLowerHalfOfCircleSegmentLoop               if (X >= 0) then loop back (more to
                                                        do)

    JMP .setGraphicsCursorPositionAndFinishPLOT         

§10. reflectCirclePointXAboutCircleCentre.

.reflectCirclePointXAboutCircleCentre = $94c6
    .circlePointRightX = centre X + .circlePointX
    CLC                                                 
    LDA .vduOldGraphicsCursorPixelsXLow                 
    ADC .circlePointXLow                                
    STA .circlePointRightXLow                           
    LDA .vduOldGraphicsCursorPixelsXHigh                
    ADC .circlePointXHigh                               
    STA .circlePointRightXHigh                          

    .circlePointLeftX = centre X - .circlePointX
    SEC                                                 
    LDA .vduOldGraphicsCursorPixelsXLow                 
    SBC .circlePointXLow                                
    STA .circlePointLeftXLow                            
    LDA .vduOldGraphicsCursorPixelsXHigh                
    SBC .circlePointXHigh                               
    STA .circlePointLeftXHigh                           
    RTS                                                 

§11. addCirclePointYToCircleCentre.

.addCirclePointYToCircleCentre = $94ed
    .circlePointLeftY  = .circlePointRightY = centre Y + .circlePointY
    CLC                                                 
    LDA .vduOldGraphicsCursorPixelsYLow                 
    ADC .circlePointYLow                                
    STA .circlePointRightYLow                           
    STA .circlePointLeftYLow                            
    LDA .vduOldGraphicsCursorPixelsYHigh                
    ADC .circlePointYHigh                               
    STA .circlePointRightYHigh                          
    STA .circlePointLeftYHigh                           
    RTS                                                 

§12. Set left and right points Y coordinate to be reflected below the centre row of the circle.

 On Entry:
       .vduOldGraphicsCursorPixelsY: centre of circle (Y coordinate)

 On Exit:
       .circlePointRightY: centre row Y - .circlePointYLow/High
       .circlePointLeftY : .circlePointRightY
.reflectPointVerticallyAboutCircleCentre = $9507
    .circlePointLeftY  = .circlePointRightY = centre Y - .circlePointY
    SEC                                                 
    LDA .vduOldGraphicsCursorPixelsYLow                 circle centre Y
    SBC .circlePointYLow                                
    STA .circlePointRightYLow                           
    STA .circlePointLeftYLow                            

    LDA .vduOldGraphicsCursorPixelsYHigh                circle centre Y
    SBC .circlePointYHigh                               
    STA .circlePointRightYHigh                          
    STA .circlePointLeftYHigh                           
    RTS                                                 

§13. Square a 16 bit number.

.square12_into4567 = $9521
    LDA .gxrTemp2                                       
    BPL +                                               

    negate values (abs)
    SEC                                                 }
    LDA #0                                              }
    SBC .gxrTemp1                                       }
    STA .gxrTemp1                                       } .gxrTemp1 = -.gxrTemp1
    LDA #0                                              } .gxrTemp2 = -.gxrTemp2
    SBC .gxrTemp2                                       }
    STA .gxrTemp2                                       }
+

    copy first parameter into second parameter (to multiply the number by itself)
    LDA .gxrTemp1                                       }
    STA .gxrTemp4                                       }
    LDA .gxrTemp2                                       } .gxrTemp45 = .gxrTemp12
    STA .gxrTemp5                                       }
    JMP .multiply16x16                                  

§14. Initialise variables for drawing a segment.

 On Entry:
   .circleRadiusSquared:
   .line1StartPoint: original end point
.segmentInitialisation = $9546
    .ellipseTempABXY = .circleRadiusSquared (remember radius squared)
    LDY #3                                              loop counter
-
    LDA .circleRadiusSquaredLow,Y                       
    STA .ellipseTempA,Y                                 
    DEY                                                 
    BPL -                                               if (not done yet) then branch (loop
                                                        back)

.calculateEndPointOnCircle = $9551
    Copy line 3 point to line 1 point
    LDY #3                                              loop counter
-
    LDA .line3StartPointX,Y                             }
    STA .line1StartPointX,Y                             } .line1StartPoint = .line3StartPoint
    DEY                                                 }
    BPL -                                               }

    At this point we know the radius (squared) of the circle we want. We walk along the end
    line from
    the centre until we reach the desired radius (squared).
    LDX #.line3StartPointX - .vduVariablesStart         line 3 = end line
    JSR .lineMoveToNextPixel                            move to next point on end line

    Get radius squared
    LDX #.line3StartPointX - .vduVariablesStart         current point along end line
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart centre of the circle
    JSR .getCircleRadiusSquared                         .circleRadiusSquaredLow is radius^2

    Is (radius based on start point)^2 >= (radius based on end point)^2?
    SEC                                                 
    LDX #3                                              loop counter
    LDY #0                                              
.circleLargerLoop = $956d
    LDA .ellipseTempA,Y                                 
    SBC .circleRadiusSquaredLow,Y                       calculate .ellipseTempABXY -
                                                        .circleRadiusSquaredLow
    INY                                                 to see which is larger
    DEX                                                 
    BPL .circleLargerLoop                               

    BCS .calculateEndPointOnCircle                      if (.circleOPQR >= (new radius)^2)
                                                        then loop back

    Now .circleRadiusSquared is the end point on the circle

    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart centre of circle (start of
                                                              line)
    LDA #.vdu25ParameterXLow - .vduVariablesStart       PLOT parameter = end point (end of
                                                        line)
    LDX #.line3StartPointX - .vduVariablesStart         where to put results
    JSR .lineInitialisation                             
    The line initialisation sets up line 3 variables:
       .line3StartPointX: initial and current point X [2 bytes]
       .line3StartPointY: initial and current point Y [2 bytes]
       .line3AbsDeltaX  : abs(deltaX)                 [2 bytes]
       .line3AbsDeltaY  : abs(deltaY)                 [2 bytes]
       .line3ErrorTerm  : Bresenham error term        [2 bytes]
       .line3Signs      : signs of deltaY (top bit) and deltaX (bit 6) [1 byte]

    LDA .circleLine2Quadrant                            
    EOR .circleLine3Quadrant                            
    AND #2                                              if (start and end lines are in the
                                                        same hemisphere,
    BEQ .return29                                       i.e. either both above or both below
                                                        the centre row) then branch (return)

    Start and end lines are in different hemispheres
    LDA .circleLine2Quadrant                                
    LSR                                                     
    LSR                                                     carry = start line is below the
                                                            centre line
    LDY #.vduGraphicsCursorPixelsXLow - .vduVariablesStart  beginning of line (start point)
    LDA #.line1StartPointX - .vduVariablesStart             end of line       (new end point
                                                            on the circle)
    LDX #.line2StartPointX - .vduVariablesStart             where to put results
    BCS +                                                   if (start line is below the
                                                            centre line) then branch

    LDY #.line1StartPointX - .vduVariablesStart             beginning of line (new end point
                                                            on the circle)
    LDA #.vduGraphicsCursorPixelsXLow - .vduVariablesStart  end of line       (start point)
    LDX #.line3StartPointX - .vduVariablesStart             where to put results
+
    STX .circleChordLine                                index of line for chord
    STA .circleChordDestinationPoint                    index of end point of chord
    JSR .lineInitialisation                             initialise line 2 or 3 to be the
                                                        chord line

    LDX .circleLine2Quadrant                            
    LDA .circleQuadrants,X                              
    AND #1                                              
    STA .circleFlag                                     which side of line to plot
.return29 = $95b3
    RTS                                                 

§15. Initialise segment when chord crosses centre row.

 When drawing a circle segment, we initialise variables again when the chord crosses the centre
 row.
.segmentInitialisationIfStraddlingTheCentreRow = $95b4
    LDA .circleLine2Quadrant                            
    EOR .circleLine3Quadrant                            
    AND #2                                              
    BEQ .return29                                       if (both lines are above the centre
                                                        line, or both below) then branch
                                                        (return)

    line 2 and line 3 quadrants are either side of the horizontal centre line
    LDA .circleLine2Quadrant                            
    LSR                                                 
    LSR                                                 
    PHP                                                 remember carry: set if start line is
                                                        below the horizontal centre line

    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   beginning of line (centre of
                                                                circle)
    LDA #.vduGraphicsCursorPixelsXLow - .vduVariablesStart      end of line (start of arc)
    LDX #.line2StartPointX - .vduVariablesStart                 where to put results
    BCS +                                                       if (line 2 is below the
                                                                centre line) then branch

    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   beginning of line (centre of
                                                                circle)
    LDA #.vdu25ParameterXLow - .vduVariablesStart               end of line (original end of
                                                                arc point)
    LDX #.line3StartPointX - .vduVariablesStart                 where to put results
+
    JSR .lineInitialisation                             

    PLP                                                 recall carry: set if start line is
                                                        below the horizontal centre line
    LDY #.vduGraphicsCursorPixelsXLow - .vduVariablesStart beginning of line (start point)
    LDA #.line1StartPointX - .vduVariablesStart         end of line       (new end point on
                                                        the circle)
    LDX #.line2StartPointX - .vduVariablesStart         where to put results
    BCC +                                               if (start line is below the centre
                                                        line) then branch

    LDY #.line1StartPointX - .vduVariablesStart         beginning of line (new end point on
                                                        the circle)
    LDA #.vduGraphicsCursorPixelsXLow - .vduVariablesStart end of line       (start point)
    LDX #.line3StartPointX - .vduVariablesStart         where to put results
+
    STX .circleChordLine                                index of line for chord
    STA .circleChordDestinationPoint                    index of end point of chord
    JMP .lineInitialisation                             initialise line 2 or 3 to be the
                                                        chord line

§16.

 Prepare line and quadrant data for a circle arc / sector / segment.

 Each circle shape is defined by a circle centre, a start point on the circle, and an end
 point.

 Circles are drawn row by row starting from the horizontal centre line upwards (and at
 the same time reflected to get the rows downward).

 To explain what's going on:
   The *start line* is from the centre to the start point of the arc / sector / segment.
   The *end line* is from the centre to the end point of the arc / sector / segment.
   The *chord line* is from the start point to the end point.

 The code tracks the start and end lines until it reaches the chord, where it replaces
 the line that just finished with the chord line.

 In the code the two lines being tracked are the .line2* and .line3* variables.

 Data used in the circle algorithms
 ----------------------------------

 Quadrants
 ---------

 We divide the screen into four quadrants, with the origin at the centre of the circle:

                             deltaY
                               /|\
                                |
                      quadrant  |  quadrant
                         1      |      0
                                |               \
                 ---------------+----------------   deltaX
                                |               /
                      quadrant  |  quadrant
                         2      |      3
                                |

 Circle quadrant data
 --------------------

 At the start of a circle routine, this function calculates a single data byte for each quadrant.
 The byte value depends on which quadrants the start and end lines are in, and (if both in the same
 quadrant) the anticlockwise order the lines appear in.

 See below for more details of what the bytes mean, but here are the byte values calculated for each
 category:

sectors.png


 +-------+--------+-------+------++-----------------------------------------------------------+
 | start | end    | start | end  ||                  circle quadrant data                     |
 | angle | angle  | quad  | quad ||  quadrant 0  |  quadrant 1  |  quadrant 2  |  quadrant 3  |
 +-------+--------+-------+------++--------------+--------------+--------------+--------------+
 |  30°  |   60°  |   0   |   0  || 3A=0011 1010 |       0      |       0      |       0      |
 |  60°  |   30°  |   0   |   0  || 57=0101 0111 |       1      |       1      |       1      |
 |  30°  |  120°  |   0   |   1  || 0A=0000 1010 | 0E=0000 1110 |       0      |       0      |
 |  30°  |  210°  |   0   |   2  || 0A=0000 1010 |       1      | 07=0000 0111 |       0      |
 |  30°  |  300°  |   0   |   3  || 0A=0000 1010 |       1      |       1      | 0E=0000 1110 |

 | 120°  |   30°  |   1   |   0  || 07=0000 0111 | 03=0000 0011 |       1      |       1      |
 | 120°  |  150°  |   1   |   1  ||       0      | 1E=0001 1110 |       0      |       0      |
 | 150°  |  120°  |   1   |   1  ||       1      | 73=0111 0011 |       1      |       1      |
 | 120°  |  210°  |   1   |   2  ||       0      | 03=0000 0011 | 07=0000 0111 |       0      |
 | 120°  |  300°  |   1   |   3  ||       0      | 03=0000 0011 |       1      | 0E=0000 1110 |

 | 210°  |   30°  |   2   |   0  || 07=0000 0111 |       0      | 0A=0000 1010 |       1      |
 | 210°  |  120°  |   2   |   1  ||       1      | 0E=0000 1110 | 0A=0000 1010 |       1      |
 | 210°  |  240°  |   2   |   2  ||       0      |       0      | 3A=0011 1010 |       0      |
 | 240°  |  210°  |   2   |   2  ||       1      |       1      | 57=0101 0111 |       1      |
 | 210°  |  300°  |   2   |   3  ||       0      |       0      | 0A=0000 1010 | 0E=0000 1110 |

 | 300°  |   30°  |   3   |   0  || 07=0000 0111 |       0      |       0      | 03=0000 0011 |
 | 300°  |  120°  |   3   |   1  ||       1      | 0E=0000 1110 |       0      | 03=0000 0011 |
 | 300°  |  210°  |   3   |   2  ||       1      |       1      | 07=0000 0111 | 03=0000 0011 |
 | 300°  |  330°  |   3   |   3  ||       0      |       0      |       0      | 1E=0001 1110 |
 | 330°  |  300°  |   3   |   3  ||       1      |       1      |       1      | 73=0111 0011 |
 +-------+--------+-------+------++--------------+--------------+--------------+--------------+

 One byte for each quadrant:

    0 means nothing to plot in the quadrant
    1 means plot in the entire quadrant

 else: (the start line and/or end line is in the quadrant)

     bit 0 = for an even quadrant, set if the end line is in the quadrant
             for an odd quadrant, set if the start line is in the quadrant
     bit 1 = set if either the start or end line is in the quadrant (always set)
     bit 2 = set if the end point is in quadrant
     bit 3 = bit 0 inverted:
             for an even quadrant, set if the start line is in the quadrant
             for an odd quadrant, set if the end line is in the quadrant
     bit 4 = set if start and end lines are in the same quadrant
     bit 5 = set if start and end lines are in the same quadrant, and start point is closer to the
             horizontal centre line
     bit 6 = set if start and end lines are in the same quadrant, and start angle is larger
     bit 7 = 0

On Exit:
  .line2*: variables for centre to start point
  .line3*: variables for centre to end point
  .circleQuadrants: four single byte values, one per quadrant (see above)

§17. circleDoLineAndQuadrantInitialisation.

.circleDoLineAndQuadrantInitialisation = $95ed
    Zero quadrant information, (one byte per quadrant, four bytes in total)
    LDY #3                                              loop counter
    LDA #0                                              
-
    STA .circleQuadrants,Y                              
    DEY                                                 
    BPL -                                               

    Line 2 is from the centre of the circle to the start point
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   beginning of line (circle
                                                                centre)
    LDA #.vduGraphicsCursorPixelsXLow - .vduVariablesStart      end of line       (arc start
                                                                point)
    LDX #.line2StartPointX - .vduVariablesStart                 where to put results
    JSR .lineInitialisation                                     
    The line initialisation sets up variables for line 2:
       .line2StartPointX: initial and current point X [2 bytes]
       .line2StartPointY: initial and current point Y [2 bytes]
       .line2AbsDeltaX  : abs(deltaX)                 [2 bytes]
       .line2AbsDeltaY  : abs(deltaY)                 [2 bytes]
       .line2ErrorTerm  : Bresenham error term        [2 bytes]
       .line2Signs      : signs of deltaY (top bit) and deltaX (bit 6) [1 byte]

    Calculate and store quadrant for line 2
    LDX #.line2StartPointX - .vduVariablesStart         
    JSR .getQuadrant                                    
    STA .circleLine2Quadrant                            

    Line 3 is from the centre of the circle to the end point
    LDY #.vduOldGraphicsCursorPixelsXLow - .vduVariablesStart   beginning of line (circle
                                                                centre)
    LDA #.vdu25ParameterXLow - .vduVariablesStart               end of line       (arc end
                                                                point)
    LDX #.line3StartPointX - .vduVariablesStart                 where to put results
    JSR .lineInitialisation                                     
    The line initialisation sets up variables for line 3:
       .line3StartPointX: initial and current point X [2 bytes]
       .line3StartPointY: initial and current point Y [2 bytes]
       .line3AbsDeltaX  : abs(deltaX)                 [2 bytes]
       .line3AbsDeltaY  : abs(deltaY)                 [2 bytes]
       .line3ErrorTerm  : Bresenham error term        [2 bytes]
       .line3Signs      : signs of deltaY (top bit) and deltaX (bit 6) [1 byte]

    Calculate and store quadrant for line 3
    LDX #.line3StartPointX - .vduVariablesStart         
    JSR .getQuadrant                                    
    STA .circleLine3Quadrant                            

    Is the line 3 quadrant the same as line 2 quadrant?
    CMP .circleLine2Quadrant                            
    BEQ .sameQuadrant                                   

    lines 2 and 3 are in different quadrants

    line 3 (centre to end point) quadrant has a value associated and stored in
    circleQuadrants array:
    
    quadrant | value  binary
           0 |  7     %0111
           1 | 14     %1110
           2 |  7     %0111
           3 | 14     %1110
    
    bit 0 = odd quadrant (which side of the start line to plot in)
    bit 1 = either start or end line in quadrant
    bit 2 = end point in quadrant
    bit 3 = even quadrant (which side of the end line to plot in)

    TAY                                                 Y = line 3 quadrant
    ROR                                                 set carry if quadrant is odd
    LDA #7                                              A=7 if line 3 quadrant is 0 or 2
    BCC +                                               if (quadrant is 0 or 2) then branch
    EOR #9                                              A=14 (quadrant is 1 or 3)  [NOTE:
                                                        could do LDA #14]
+
    STA .circleQuadrants,Y                              store in offset for the relevant
                                                        quadrant

    line 2 (centre to start point) quadrant has a value associated and stored in
    circleQuadrants array:
    
    quadrant | value  binary
           0 | 10     %1010
           1 |  3     %0011
           2 | 10     %1010
           3 |  3     %0011
    
    bit 0 = even quadrant (which side of the start line to fill in)
    bit 1 = either start or end line in quadrant
    bit 2 = end point in quadrant
    bit 3 = odd quadrant (which side of the end line to fill in)

    LDA .circleLine2Quadrant                            
    TAY                                                 Y = line 2 quadrant
    ROR                                                 set carry if quadrant is odd
    LDA #10                                             A=10 if line 2 quadrant is 0 or 2
    BCC .fillQuadrantDataLoop                           if (quadrant is 0 or 2) then branch
    EOR #9                                              A=3 (quadrant is 1 or 3)   [NOTE:
                                                        could do LDA #3]
    BCS .fillQuadrantDataLoop                           ALWAYS branch

.sameQuadrant = $9636
    Copy line 2 abs(deltaY) and line 3 abs(deltaX) in order to multiply them.
    This is then used to test which line is further around the circle anticlockwise
    LDY #1                                              loop counter
-
    LDA .line2AbsDeltaY,Y                               
    STA .multiplicand0,Y                                
    LDA .line3AbsDeltaX,Y                               
    STA .multiplier0,Y                                  
    DEY                                                 
    BPL -                                               

    JSR .multiply16x16                                  .line2AbsDeltaY * .line3AbsDeltaX

    Copy 32 bit result into .circleSlopeTest
    LDY #3                                              
-
    LDA .product0,Y                                     
    STA .circleSlopeTestLow,Y                           
    DEY                                                 
    BPL -                                               

    Copy line 2 abs(deltaX) and line 3 abs(deltaY) in order to multiply them
    This is then used to test which line is further around the circle anticlockwise
    LDY #1                                              loop counter
-
    LDA .line3AbsDeltaY,Y                               
    STA .multiplicand0,Y                                
    LDA .line2AbsDeltaX,Y                               
    STA .multiplier0,Y                                  
    DEY                                                 
    BPL -                                               

    JSR .multiply16x16                                  .line3AbsDeltaY * .line2AbsDeltaX

    LDX #3                                              loop counter
    LDY #0                                              index
    LDA .circleLine2Quadrant                            
    ROR                                                 
    BCS .checkWhichIsLargerLoop2                        if (line 2 quadrant is 1 or 3) then
                                                        branch

    Which is larger: .circleSlopeTest or .product0
    i.e. (.line2AbsDeltaY * .line3AbsDeltaX) or (.line3AbsDeltaY * .line2AbsDeltaX)
    i.e. (.line2AbsDeltaY / .line2AbsDeltaX) or (.line3AbsDeltaY / .line3AbsDeltaX)
    i.e. testing which line has the larger slope (rearranged to avoid expensive
         divisions and division by zero issues).
    SEC                                                 
.checkWhichIsLargerLoop1 = $9674
    LDA .product0,Y                                     
    SBC .circleSlopeTestLow,Y                           
    INY                                                 
    DEX                                                 
    BPL .checkWhichIsLargerLoop1                        
    BMI .doneChecking                                   ALWAYS branch

    Which is larger, .product0 or .circleSlopeTest
.checkWhichIsLargerLoop2 = $9680
    LDA .circleSlopeTestLow,Y                           
    SBC .product0,Y                                     
    INY                                                 
    DEX                                                 
    BPL .checkWhichIsLargerLoop2                        

.doneChecking = $968a
    Carry holds which slope is bigger (i.e. which line is sloped further away from the X
    axis)
    Adjust values as needed
    LDA #%00111010                                      
    BCS +                                               
    EOR #%01101101                                      
+
    ROR .circleLine2Quadrant                            
    BCC +                                               
    EOR #%00100100                                      
+
    ROL .circleLine2Quadrant                            
    LDY .circleLine2Quadrant                            
    STA .circleQuadrants,Y                              store value in quadrant data
    BCS .return21                                       

.fillQuadrantDataLoop = $96a2
    Fill each quadrant between the start line quadrant to the end line quadrant going
    anticlockwise. Fill with the value 1 (all of quadrant can be plotted). The remaining
    quadrants store zero as initialised at the top of the routine.
    STA .circleQuadrants,Y                              store value in quadrant data
    INY                                                 }
    TYA                                                 } move to next quadrant anticlockwise
    AND #3                                              }
    CMP .circleLine3Quadrant                            have we reached the end quadrant
    BEQ .return21                                       if (same quadrant as line 3) then
                                                        branch (return)

    TAY                                                 new quadrant back into Y
    LDA #1                                              new value to store
    JMP .fillQuadrantDataLoop                           

.return21 = $96b4
    RTS                                                 

§18. Get the quadrant of the line's direction.

                             deltaY
                               /|\
                                |
                      quadrant  |  quadrant
                         1      |      0
                                |               \
                 ---------------+----------------   deltaX
                                |               /
                      quadrant  |  quadrant
                         2      |      3
                                |

 On Entry:
   X: index of line to check
 On Exit:
   A: quadrant of line
.getQuadrant = $96b5
    LDA .vduVariablesStart + 10,X                       look at the line signs
    AND #$C0                                            just the top two bits
    ASL                                                 
    BCS .negativeDeltaY                                 if (deltaY < 0) then branch

    ROL                                                 A = 0, carry = sgn(deltaX)
    ROL                                                 A = 0 if deltaX>=0
    RTS                                                 A = 1 if deltaX<0

.negativeDeltaY = $96c0
    ROL                                                 carry = sgn(deltaX), A=1
    ROL                                                 (A = 2 if deltaX>=0)
                                                        (A = 3 if deltaX<0)
    EOR #1                                              A = 2 if deltaX<0
                                                        A = 3 if deltaX>=0
    RTS                                                 

§19. Circle arc / sector / segment quadrant preparation.

 On Entry:
   Y is quadrant to use
   .circlePointRight: point on circle to the right
   .circlePointLeft:  point on circle to the left
 On Exit:
   .circleTrackingLeftmostChordPoint:
   .circleTrackingSecondLineInQuadrant:
   .circleRadialLine:
   .circleTrackingRightmostChordPoint:
.circlePrepareForRightSideQuadrant = $96c5
    LDA #.circlePointRightXLow - .vduVariablesStart     
    STA .circleTrackingLeftmostChordPoint               leftmost point = right point
    LDA #0                                              
    STA .circleTrackingSecondLineInQuadrant             
    STA .circleRadialLine                               radial line = 0

    JSR .circlePrepareForLeftSideQuadrant               prepare for left side, then swap
                                                        results

    Copy left result into right side
    LDA .circleTrackingLeftmostChordPoint               
    STA .circleTrackingRightmostChordPoint              

    LDA .circleTrackingSecondLineInQuadrant             }
    PHA                                                 }
    LDA .circleRadialLine                               } swap second line and radial line
    STA .circleTrackingSecondLineInQuadrant             }
    PLA                                                 }
    STA .circleRadialLine                               }

    LDA #.circlePointLeftXLow - .vduVariablesStart      
    STA .circleTrackingLeftmostChordPoint               .circleTrackingLeftmostChordPoint =
                                                        left point
    RTS                                                 

§20. Circle arc / sector / segment quadrant preparation.

 Updates line tracking for the given quadrant. Used for the left hand quadrants 1,2 but also
 called by the right hand quadrant code (.circlePrepareForRightSideQuadrant above) with quadrant
 values 0, 3.

 On Entry:
   Y: quadrant to prepare (0-3)
   .circlePointLeft: point on circle to the right
   .circlePointRight: point on circle to the left
   .circleQuadrants: line information about each quadrant
   .circleTrackingLeftmostChordPoint : index of point on circle
   .circleTrackingSecondLineInQuadrant:
   .circleRadialLine:

 On Exit:
   .circleTrackingLeftmostChordPoint : which line to check against when deciding whether
                                       to plot; zero means nothing to plot in this quadrant
   .circleTrackingSecondLineInQuadrant:
   .circleRadialLine:
.circlePrepareForLeftSideQuadrant = $96ef
    LDA #0                                              
    STA .circleQuadrantDataShifter                      how many times to shift the quadrant
                                                        data when starting to track the chord
    LDA .circleQuadrants,Y                              

    .circleQuadrants stores one byte for each quadrant:
    
       0 means nothing to plot in the quadrant
       1 means plot in the entire quadrant
    
    else: (the start line and/or end line is in the quadrant)
    
        bit 0 = for an even quadrant, set if the end line is in the quadrant
                for an odd quadrant, set if the start line is in the quadrant
                This determines if plotting is wanted to the left of the line in the left
    side quadrant
        bit 1 = set if either the start or end line is in the quadrant (always set)
        bit 2 = set if the end point is in quadrant
        bit 3 = bit 0 inverted:
                for an even quadrant, set if the start line is in the quadrant
                for an odd quadrant, set if the end line is in the quadrant
        bit 4 = set if start and end lines are in the same quadrant
        bit 5 = set if start and end lines are in the same quadrant, and start point is
    closer to the horizontal centre line
        bit 6 = set if start and end lines are in the same quadrant, and start angle is
    larger
        bit 7 = 0

    LSR                                                 
    BNE .lineFoundInQuadrant                            if (a line is in the quadrant) then
                                                        branch

    No line in quadrant
    BCS .return22                                       if (plot in the entire quadrant)
                                                        then branch (return)
    STA .circleTrackingLeftmostChordPoint               if (nothing in this quadrant to
                                                        plot) then (return with
                                                        .circleTrackingLeftmostChordPoint =
                                                        0)
.return22 = $96ff
    RTS                                                 

.lineFoundInQuadrant = $9700
    At least one of the two lines is within the quadrant.
    PHP                                                 push carry flag (was bit 0)
    LSR                                                 
    LSR                                                 carry = set if end line is in
                                                        quadrant Y
    STY .circleCurrentQuadrant                          remember Y (current quadrant)

    We have a start line (line 2) and an end line (line 3).
    We make sure X is set to the index of the line that is within the quadrant, and Y is the
    other line.
    LDX #.line2StartPointX - .vduVariablesStart         } X is the line we are tracking (the
                                                        } start line), Y is the other line
                                                        } (the end line)
    LDY #.line3StartPointX - .vduVariablesStart         } (used when the end line is not in
                                                        } the quadrant)
    BCC +                                               if (end line not in quadrant) then
                                                        branch

    End line in quadrant, use X=end line
    LDX #.line3StartPointX - .vduVariablesStart         } X is the line we are tracking (the
                                                        } end line), Y is the other line
                                                        } (the start line)
    LDY #.line2StartPointX - .vduVariablesStart         } used when the end line is in the
                                                        } quadrant
+

    STY .circleSecondaryLine                            remember the second line (we might
                                                        need to track it, if it's also in
                                                        the same quadrant)
    LDY .circleTrackingLeftmostChordPoint               index of point on circle at left end
                                                        of chord
    PLP                                                 recall carry flag (from bit 0: which
                                                        side of line in quadrant to plot)
    BCS .canPlotLeftOfLineInQuadrant                    if (side of line to plot is one way)
                                                        then branch

    Can plot to the right of the line in the quadrant.
    Update this line until we reach a new row.
    JSR .updateLineAndMoveToNextRow                     
    BPL .stillTrackingLineA                             if (we are still tracking the line)
                                                        then branch

    Start tracking along the chord instead of the start or end line that has just finished
    JSR .startTrackingChord                             
    LDY .circleCurrentQuadrant                          recall current quadrant
    JMP .circlePrepareForLeftSideQuadrant               loop back

.stillTrackingLineA = $9727
    BNE +                                               
    STX .circleTrackingLeftmostChordPoint               
+
    LDX .circleCurrentQuadrant                          recall current quadrant
    LDA .circleQuadrants,X                              
    AND #$F0                                            
    BEQ .startTrackingChordLocal1                       if (no second line in quadrant) then
                                                        branch

    Tracking two lines in the quadrant, update the second line
    LDX .circleSecondaryLine                            recall the secondary line we are
                                                        tracking
    JSR .updateLineToEndOfRow                           
    BEQ +                                               if (line has not yet reached the
                                                        circle point) then branch

    Second line has reached circle
    LDA #2                                              
    STA .circleQuadrantDataShifter                      how many times to shift the quadrant
                                                        data when starting to track the chord

+
    STX .circleTrackingSecondLineInQuadrant             remember line we are tracking (the
                                                        second line in the quadrant)
.startTrackingChordLocal1 = $9746
    JMP .startTrackingChordWithCorrectQuadrantData      


    Similar to above code
.canPlotLeftOfLineInQuadrant = $9749
    Can plot to the left of the line in the quadrant.
    Update this line until we reach a new row.
    JSR .updateLineToEndOfRow                           
    BPL .stillTrackingLineB                             if (we are still tracking the line)
                                                        then branch

    Start tracking along the chord instead of the start or end line that has just finished
    JSR .startTrackingChord                             
    LDY .circleCurrentQuadrant                          recall current quadrant
    JMP .circlePrepareForLeftSideQuadrant               loop back

.stillTrackingLineB = $9757
    STX .circleTrackingSecondLineInQuadrant             remember line we are tracking (the
                                                        second line in the quadrant)
    LDX .circleCurrentQuadrant                          recall current quadrant
    LDA .circleQuadrants,X                              
    AND #$F0                                            check if we are tracking two lines
                                                        in the quadrant
    BEQ .startTrackingChordLocal2                       if (no second line in quadrant) then
                                                        branch

    Tracking two lines in the quadrant, update the second line
    LDX .circleSecondaryLine                            recall the secondary line we are
                                                        tracking
    JSR .updateLineAndMoveToNextRow                     
    BEQ .secondLineNotReachedCircleYet                  if (not yet reached circle) then
                                                        branch

    Second line has reached circle
    LDA #2                                              
    STA .circleQuadrantDataShifter                      how many times to shift the quadrant
                                                        data when starting to track the chord

.secondLineNotReachedCircleYet = $9771
    STX .circleRadialLine                               remember second line we are tracking
.startTrackingChordLocal2 = $9774
    JMP .startTrackingChordWithCorrectQuadrantData      [NOTE: Redundant, could just fall
                                                        through]

§21. startTrackingChordWithCorrectQuadrantData.

.startTrackingChordWithCorrectQuadrantData = $9777
    DEC .circleQuadrantDataShifter                      how many times to shift the quadrant
                                                        data when starting to track the chord
    BMI .return24                                       if (done) then return

    JSR .startTrackingChord                             
    Shift quadrant data bits down and start tracking the chord line
    JMP .startTrackingChordWithCorrectQuadrantData      

.return24 = $9782
    RTS                                                 

§22. We have reached the start of the chord.

 We track the chord line by reusing line 2 or line 3, i.e. reusing the start or end line
 that we have just finished tracking.

 On Exit:
   X, .circleChordLine:            index of the current chord line
   .circleChordDestinationPoint:   index of the end of the chord point
.startTrackingChord = $9783
    LDX .circleCurrentQuadrant                          

    Shift quadrant data down three bits
    LDA .circleQuadrants,X                              }
    LSR                                                 }
    LSR                                                 } shift right quadrant data by three
                                                        } bits
    LSR                                                 } carry = which side of line to plot
                                                        } (for end line)
    STA .circleQuadrants,X                              }
    AND #1                                              
    STA .circleFlag                                     which side of line to plot

    LDA .circleChordLine                                }
    BEQ +                                               } clear chord line
    LDA #0                                              } [NOTE: Redundant, .circleChordLine
                                                        } is set below]
    STA .circleChordLine                                }
+
    LDY #.line2StartPointX - .vduVariablesStart             line from: current point along
                                                            start line
    LDA #.line1StartPointX - .vduVariablesStart             line to:   point on circle at
                                                            end line
    LDX #.line2StartPointX - .vduVariablesStart             where to put results
    BCC +                                                   if (which side of line to plot)
                                                            then branch

    LDY #.line3StartPointX - .vduVariablesStart             line from: current point on end
                                                            line
    LDA #.vduGraphicsCursorPixelsXLow - .vduVariablesStart  line to: initial arc start point
    LDX #.line3StartPointX - .vduVariablesStart             where to put results
+
    STX .circleChordLine                                index of chord line
    STA .circleChordDestinationPoint                    index of end of chord point
    JMP .lineInitialisation                             start tracking the chord line

§23. Updates tracking the position along the current line.

 ... until we either:
       (a) move incrementally to a new row (the common case),
       (b) hit the given point on the circle (marking the end of the line tracking), or
       (c) reach the same X as the point on the circle but not the same Y

 On Entry:
   X: index of line
   Y: index of circle point

 On Exit:
   Zero flag: non-zero if the line has reached the circle. We don't need to continue tracking
      the line any further.
   Negative flag: set if the Y coordinates don't match but the X coordinates do.

   Preserves X,Y
.updateLineToEndOfRow = $97b5
    We first compare the current point along the line (indexed by the X register)
    against the current point on the circle (indexed by the Y register)

    If Y coordinate doesn't match, then branch
    LDA .vduVariablesStart+2,Y                          
    CMP .vduVariablesStart+2,X                          
    BNE .yCoordinatesDontMatch                          

    LDA .vduVariablesStart+3,Y                          
    CMP .vduVariablesStart+3,X                          
    BNE .yCoordinatesDontMatch                          

    Y coordinates match. If X coordinates don't match, then return 0 else return 1
    LDA .vduVariablesStart,Y                            
    CMP .vduVariablesStart,X                            
    BNE .xCoordinatesDontMatch                          

    LDA .vduVariablesStart+1,Y                          
    CMP .vduVariablesStart+1,X                          
    BNE .xCoordinatesDontMatch                          

    Both the X and Y coordinates match the circle position.
    INC .circleQuadrantDataShifter                      how many times to shift the quadrant
                                                        data when starting to track the chord
    LDA #1                                              finished tracking line
    RTS                                                 

.xCoordinatesDontMatch = $97db
    LDA #0                                              not finished tracking line
    RTS                                                 

.yCoordinatesDontMatch = $97de
    Check X if coordinates match
    LDA .vduVariablesStart,Y                            
    CMP .vduVariablesStart,X                            
    BNE .moveAlongRow                                   

    LDA .vduVariablesStart+1,Y                          
    CMP .vduVariablesStart+1,X                          
    BEQ .rorAndReturn                                   if (X coordinates match) then branch
                                                        (note that carry is set in this case)

.moveAlongRow = $97ee
    Move one pixel along the line (preserving X and Y registers) and loop back to try again
    STX .vduTempStoreDE                                 }
    STY .vduTempStoreDF                                 } remember X,Y

    JSR .lineMoveToNextPixel                            move to next point on line X

    LDX .vduTempStoreDE                                 } recall X,Y
    LDY .vduTempStoreDF                                 }
    JMP .updateLineToEndOfRow                           

.rorAndReturn = $97fc
    ROR                                                 carry (always set in practice)
                                                        is shifted into top bit of A,
    RTS                                                 setting the Negative flag.

§24. Update the line until we reach a new row, then move to that new row.

 On Entry:
   X: index of the line we are updating
   Y: index of point on the circle

 On Exit:
   Zero flag: non-zero if the line has reached the circle. We don't need to continue tracking
      the line any further.
   Negative flag: set if the X coordinates match but the Y coordinates don't.
.updateLineAndMoveToNextRow = $97fe
    JSR .updateLineToEndOfRow                           
    BEQ .moveToNextRow                                  if (not yet reached the point on the
                                                        circle) then branch
    RTS                                                 [NOTE: Could use BNE .return20]

.moveToNextRow = $9804
    LDA .vduVariablesStart,Y                            } check line X coordinates to see if
                                                        } they match
    CMP .vduVariablesStart,X                            } if not, then branch
    BNE .xCoordsDontMatch                               }

    LDA .vduVariablesStart+1,Y                          }
    CMP .vduVariablesStart+1,X                          }
    BNE .xCoordsDontMatch                               }

    X coordinates match, we have reached the end of the row. Move to the next row and stop.
    ROL                                                 negative flag = bit 6 of high byte
                                                        of X coordinate [NOTE: why?]
    INC .circleQuadrantDataShifter                      how many times to shift the quadrant
                                                        data when starting to track the chord
    RTS                                                 

.xCoordsDontMatch = $9819
    CLC                                                 
    LDA .vduVariablesStart+9,X                          }
    AND #$80                                            } get sign of the error term (top
                                                        } bit)
    ROL                                                 carry = sign of error term, A=0
    BCS .return20                                       if (error term < 0) then branch
                                                        (return)

    Move one pixel along the line (preserving X and Y registers) then loop back to try again
    STX .vduTempStoreDE                                 }
    STY .vduTempStoreDF                                 } remember X,Y
    JSR .lineMoveToNextPixel                            move to next point on line X
    LDX .vduTempStoreDE                                 } recall X,Y
    LDY .vduTempStoreDF                                 }

    JMP .moveToNextRow                                  

.return20 = $9830
    RTS                                                 [NOTE: this can be removed and the
                                                        previous RTS instruction used
                                                        instead]

§25. When drawing a circle segment, update the position along the chord.

 Moves the position along the chord on the current row until we reach the point of moving
 to the next row.

 On Entry:
   .circleChordLine: index of chord point
   .circleChordDestinationPoint: index of destination point for chord
   .circleFlag: set if on a new row
   .circlePointLeftY: Y coordinate of point on circle

 Line drawing/tracking variables
.advanceAlongChordLineUntilNewRow = $9831
    First test that we are on the same Y coordinate as the current point on the circle.
    If not then we loop until we are. Then we start tracking horizontally.
    LDX .circleChordLine                                
    LDA .vduVariablesStart+2,X                          get Y position along chord, compare
                                                        it to current Y position on circle
    CMP .circlePointLeftYLow                            current Y coordinate on circle
    BNE .trackingChordLineVertically                    if (current point Y != .point on
                                                        circle Y) then branch (update error
                                                        term and try again)

    LDA .vduVariablesStart+3,X                          
    CMP .circlePointLeftYHigh                           current Y coordinate on circle
    BEQ .trackingChordLineHorizontally                  

.trackingChordLineVertically = $9844
    JSR .lineMoveToNextPixel                            move to next point on line X
    JMP .advanceAlongChordLineUntilNewRow               

§26. trackingChordLineHorizontally.

.trackingChordLineHorizontally = $984a
    LDA .circleFlag                                     
    BEQ .return23                                       

.moveAlongChordHorizontallyLoop = $984f
    Check if the current chord X position equals the current circle X position
    LDY .circleChordDestinationPoint                    check if chord line's current X
                                                        position
    LDA .vduVariablesStart,X                            equals the chord destination point.
    CMP .vduVariablesStart,Y                            
    BNE +                                               

    LDA .vduVariablesStart+1,X                          
    CMP .vduVariablesStart+1,Y                          
    BEQ .return23                                       if equal then return

    X coordinates don't match.
    If ready for a new row, then return
+
    LDA .vduVariablesStart+9,X                          get error term
    ROL                                                 }
    BCS .return23                                       } if (error term < 0) then return
                                                        } [NOTE: could use BMI .return23
                                                        } without the ROL?]

    Move to next pixel along chord line
    JSR .lineMoveToNextPixel                            move to next point on line X
    LDX .circleChordLine                                
    JMP .moveAlongChordHorizontallyLoop                 

.return23 = $9871
    RTS