def bore_circle_ID(Z_safe, stock_thickness, cut_per_pass, target_depth,
                   cutter_diameter, circle_diameter):
    """use G2; from specified diameter and thickness;
       cutter compensation in function.
       Note that this method mixes ABSOLUTE with INCREMENTAL modes:
       all moves in XY are in INCR and all moves in Z are ABS."""

    assert cutter_diameter <= circle_diameter, "bit is too large for desired hole"
    assert Z_safe > stock_thickness, "Z_safe is too short for stock thickness"

    # alternate path: do a straight drill
    if cutter_diameter == circle_diameter:
        file_text = G.set_ABS_mode()
        file_text += G.G0_Z(stock_thickness)
        file_text += G.G1_Z(target_depth)
        file_text += G.set_dwell(0.5)
        file_text += G.G0_Z(Z_safe)
        return file_text

    off_set = (circle_diameter - cutter_diameter) / 2.0

    file_text = G.set_ABS_mode()
    file_text += G.G0_Z(Z_safe)
    # XY-plane move to starting point
    file_text += G.set_INCR_mode()
    file_text += G.G0_XY((-off_set, 0))
    # Z-axis move to starting point
    file_text += G.set_ABS_mode()
    file_text += G.G0_Z(stock_thickness)
    while stock_thickness > target_depth:
        stock_thickness -= cut_per_pass
        if stock_thickness < target_depth:
            stock_thickness = target_depth
        # Z-axis move
        file_text += G.set_ABS_mode()
        file_text += G.G1_Z(stock_thickness)
        # XY-plane arc move
        file_text += G.G2XY_to_INCR_FULL((0, 0), (off_set, 0))
    # At end of cut, ensures that the program reaches the very bottom
    file_text += G.set_dwell(0.5)
    # Z-axis move
    # TODO: move this to before the return to origin
    file_text += G.set_ABS_mode()
    file_text += G.G0_Z(Z_safe)
    # Then put the bit back to (0,0)
    file_text += G.set_INCR_mode()
    file_text += G.G0_XY((off_set, 0))
    return file_text
def bore_circle_ID(Z_safe, stock_thickness, cut_per_pass, target_depth,
              cutter_diameter, circle_diameter):
    '''use G2; from specified diameter and thickness;
       cutter compensation in function.
       Note that this method mixes ABSOLUTE with INCREMENTAL modes:
       all moves in XY are in INCR and all moves in Z are ABS.'''

    assert cutter_diameter <= circle_diameter, "bit is too large for desired hole"
    assert Z_safe > stock_thickness, "Z_safe is too short for stock thickness"

    # alternate path: do a straight drill
    if cutter_diameter == circle_diameter:
        file_text = G.set_ABS_mode()
        file_text += G.G0_Z(stock_thickness)
        file_text += G.G1_Z(target_depth)
        file_text += G.set_dwell(0.5)
        file_text += G.G0_Z(Z_safe)
        return file_text

    off_set = (circle_diameter  - cutter_diameter) / 2.0

    file_text = G.set_ABS_mode()
    file_text += G.G0_Z(Z_safe)
    # XY-plane move to starting point
    file_text += G.set_INCR_mode()
    file_text += G.G0_XY((-off_set, 0))
    # Z-axis move to starting point
    file_text += G.set_ABS_mode()
    file_text += G.G0_Z(stock_thickness)
    while stock_thickness > target_depth:
        stock_thickness -= cut_per_pass
        if stock_thickness < target_depth:
            stock_thickness = target_depth
        # Z-axis move 
        file_text += G.set_ABS_mode()
        file_text += G.G1_Z(stock_thickness)
        # XY-plane arc move
        file_text += G.G2XY_to_INCR_FULL((0,0),(off_set, 0))
    # At end of cut, ensures that the program reaches the very bottom
    file_text += G.set_dwell(0.5)
    # Z-axis move
    # TODO: move this to before the return to origin
    file_text += G.set_ABS_mode()
    file_text += G.G0_Z(Z_safe)
    # Then put the bit back to (0,0)
    file_text += G.set_INCR_mode()
    file_text += G.G0_XY((off_set, 0))
    return file_text