# Copyright (C) 2022 Justin Schuh <code@justinschuh.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.

[gcode_macro set_draw_params]
description: Sets the default parameters used by DRAW_LINE_TO.
  Usage: SET_DRAW_PARAMS [HEIGHT=<mm>] [WIDTH=<mm>] [FEEDRATE=<mm/m>]
variable_height: 0.2
variable_width: 0.0 # Set to nozzle_diameter at startup
variable_feedrate: 1200
gcode:
  {% set dparams = printer["gcode_macro set_draw_params"] %}
  {% for k in params %}
    {% set kl = k|lower %}
    {% if kl in dparams %}
      {% if dparams[kl] is float %}
        {% set v = params[k]|float %}
      {% elif dparams[kl] is integer %}
        {% set v = params[k]|int %}
      {% endif %}
      SET_GCODE_VARIABLE MACRO=set_draw_params VARIABLE={kl} VALUE="{v}"
    {% endif %}
  {% endfor %}

[gcode_macro draw_line_to]
description: Extrudes a line of filament at the specified height and width from the current coordinate to the supplied XY coordinate. (The height is used only to calculate the extrusion volume.)
  Usage: DRAW_LINE_TO [X=<pos>] [Y=<pos>] [HEIGHT=<mm>] [WIDTH=<mm>]
                      [FEEDRATE=<mm/m>]
gcode:
  {% set dparams = printer["gcode_macro set_draw_params"] %}
  {% set position = printer.gcode_move.position %}
  {% set X = params.X|default(position.x)|float %}
  {% set Y = params.Y|default(position.y)|float %}
  {% set HEIGHT = params.HEIGHT|default(dparams.height)|float %}
  {% set WIDTH = params.WIDTH|default(dparams.width)|float %}
  {% set FEEDRATE = params.FEEDRATE|default(dparams.feedrate)|int %}

  {% set distance = ((X - position.x) ** 2 + (Y - position.y) ** 2) ** 0.5 %}

  {% set filament_area = 3.14159 *
       (printer.configfile.settings[
          printer.toolhead.extruder].filament_diameter ** 2) / 4 %}
  {% set E = distance * ((WIDTH * HEIGHT) / filament_area) %}

  # Use the base state call here so offset adjustments get persisted.
  _KM_SAVE_GCODE_STATE NAME=_KM_PURGE
  G90
  G92 E0.0
  G1 X{"%.3f" % X} Y{"%.3f" % Y} E{"%.5f" % E} F{FEEDRATE}
  _KM_RESTORE_GCODE_STATE NAME=_KM_PURGE MOVE=0

[gcode_macro draw_purge_line]
description: Purges the specified length of filament as a line (or rows of lines) in front of the supplied print area. If no print area is specified the purge lines are drawn at the front edge of the maximum printable area. If no printable area is set it defaults to the XY axis limits.
  Usage: DRAW_PURGE_LINE [PRINT_MIN=<X,Y>] [PRINT_MAX=<X,Y>] [HEIGHT=<mm>]
                         [WIDTH=<mm>] [LENGTH=<mm>]
gcode:
  # TODO: Make this work for delta printers.
  {% set km = printer["gcode_macro _km_globals"] %}
  {% if "PRINT_MIN" in params %}
    {% set PRINT_MIN = (
        (params.PRINT_MIN.split(",")[0]|float, km.print_min[0])|max,
        (params.PRINT_MIN.split(",")[1]|float, km.print_min[1])|max
      ) %}
  {% else %}
    {% set PRINT_MIN = km.print_min %}
  {% endif %}
  {% if "PRINT_MAX" in params %}
    {% set PRINT_MAX = (
        (params.PRINT_MAX.split(",")[0]|float, km.print_max[0])|min,
        (params.PRINT_MAX.split(",")[1]|float, km.print_max[1])|min
      ) %}
  {% else %}
    {% set PRINT_MAX = km.print_max %}
  {% endif %}
  {% set extruder = printer.toolhead.extruder|string %}
  {% set HEIGHT = params.HEIGHT|default(
    printer.configfile.settings[extruder].nozzle_diameter * 0.625)|float %}
  {% set WIDTH = params.WIDTH|default(
    printer.configfile.settings[extruder].nozzle_diameter * 1.25)|float %}
  {% set LENGTH = params.LENGTH|default(km.start_purge_length)|float %}

  {% set dparams = printer["gcode_macro set_draw_params"] %}
  {% set filament_area = 3.14159 *
       (printer.configfile.settings[extruder].filament_diameter ** 2) / 4 %}
  {% set purge_length = (LENGTH * filament_area) / (WIDTH * HEIGHT) %}
  {% set printable_length = PRINT_MAX[0] - PRINT_MIN[0] %}
  {% set purge_rows = (purge_length / printable_length)|round(0,'ceil')|int %}
  {% set printable_inset = (printable_length - purge_length / purge_rows) / 2 %}
  {% set PRINT_MIN = (PRINT_MIN[0] + printable_inset, PRINT_MIN[1]) %}
  {% set PRINT_MAX = (PRINT_MAX[0] - printable_inset, PRINT_MAX[1]) %}
  # This will purge into the print area when the bed is filled to the front.
  {% set y_start = (km.print_min[1], PRINT_MIN[1] - km.start_purge_clearance -
                                       (purge_rows + 0.5) * WIDTH )|max %}
  G90
  # Jog to the front left corner to get strings out of the print area.
  G1 X{"%.3f" % (PRINT_MIN[0] - 30, km.print_min[0])|max} Y{
    "%.3f" % (y_start - 10, km.print_min[1])|max} F{km.travel_speed_xy}
  # Move to the starting corner.
  G1 X{"%.3f" % (PRINT_MIN[0] - 2, km.print_min[0])|max} Y{"%.3f" % y_start} Z{
    "%.4f" % HEIGHT} F{km.travel_speed_xy}
  # Prime the extruder before beginning the purge lines.
  G92 E0.0
  G1 E{"%.3f" % km.start_purge_prime_length} F{km.load_priming_speed}
  G92 E0.0
  # Purge.
  G1 X{"%.3f" % PRINT_MIN[0]} F{km.travel_speed_xy}
  {% for n in range(purge_rows - 1) %}
    {% set x_pos = PRINT_MIN[0] if n % 2 else PRINT_MAX[0] %}
    DRAW_LINE_TO HEIGHT="{HEIGHT}" WIDTH="{WIDTH}" X="{x_pos}" Y="{
      WIDTH * n + y_start}"
    DRAW_LINE_TO HEIGHT="{HEIGHT}" WIDTH="{WIDTH}" X="{x_pos}" Y="{
      WIDTH * (n + 1) + y_start}"
  {% endfor %}
  {% set x_pos = PRINT_MAX[0] if purge_rows % 2 else PRINT_MIN[0] %}
  DRAW_LINE_TO HEIGHT="{HEIGHT}" WIDTH="{WIDTH}" X="{x_pos}" Y="{
    WIDTH * (purge_rows - 1) + y_start}"
  G92 E0.0
