From 3f5d45a340845aaf5c8e70b4abcb48cd0af40f4b Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 08:37:58 +0100 Subject: [PATCH 01/12] Removed fig.show from plot function, cicd testing still present --- fullcontrol/visualize/plotly.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fullcontrol/visualize/plotly.py b/fullcontrol/visualize/plotly.py index 14a9d98..a923a10 100644 --- a/fullcontrol/visualize/plotly.py +++ b/fullcontrol/visualize/plotly.py @@ -153,9 +153,7 @@ def plot(data: PlotData, controls: PlotControls): fig.update_layout(width=500, height=500) # cicd_testing is a flag set by the CICD testing script (as a temporary environmental variable) to save the plot as a .png file - if not cicd_testing: - fig.show() - else: + if cicd_testing: import plotly.io as pio from datetime import datetime pio.write_image(fig, datetime.now().strftime("figure__%d-%m-%Y__%H-%M-%S.png")) From 7ee92ebb7ea33584c21a014689a253eef69b5dbd Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 08:50:48 +0100 Subject: [PATCH 02/12] Tentative fix to double show bug. Added new plot_control called return_fig to allow for selective figure return or legacy fig show behaviour. --- fullcontrol/visualize/controls.py | 2 ++ fullcontrol/visualize/steps2visualization.py | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/fullcontrol/visualize/controls.py b/fullcontrol/visualize/controls.py index 9453e39..26e19a4 100644 --- a/fullcontrol/visualize/controls.py +++ b/fullcontrol/visualize/controls.py @@ -19,6 +19,7 @@ class PlotControls(BaseModel): hide_axes (Optional[bool]): Whether to hide axes in the plot. Default is False. neat_for_publishing (Optional[bool]): Whether to optimize the plot for publishing. Default is False. raw_data (Optional[bool]): Whether to show raw data in the plot. Default is False. + return_fig (Optional[bool]): Whether to return the plotly figure object (True) or show it with returning (False). Defaults to False to match backwards compatability. printer_name (Optional[str]): The name of the printer. Default is 'generic'. initialization_data (Optional[dict]): Information about initial printing conditions. Default is an empty dictionary. Values passed for initialization_data overwrite the default initialization_data of the printer. """ @@ -33,6 +34,7 @@ class PlotControls(BaseModel): hide_axes: Optional[bool] = False neat_for_publishing: Optional[bool] = False raw_data: Optional[bool] = False + return_fig: Optional[bool] = False printer_name: Optional[str] = 'generic' # initialization_data is information about initial printing conditions, which may be changed by the fullcontrol 'design', whereas the above attributes are never changed by the 'design' initialization_data: Optional[dict] = {} # values passed for initialization_data overwrite the default initialization_data of the printer diff --git a/fullcontrol/visualize/steps2visualization.py b/fullcontrol/visualize/steps2visualization.py index 6d35a7e..23d26f1 100644 --- a/fullcontrol/visualize/steps2visualization.py +++ b/fullcontrol/visualize/steps2visualization.py @@ -14,7 +14,7 @@ def visualize(steps: list, plot_controls: PlotControls, show_tips: bool): - plot_controls (PlotControls, optional): The style of the plot can be adjusted by passing a PlotControls instance. Returns: - - PlotData if `plot_controls.raw_data` is True, otherwise the Plotly Figure. + - PlotData if `plot_controls.raw_data` is True. Or return Plotly figure object of `plot_controls.return_fig` is True. Otherwise return nothing and show figure (matches legacy behaviour). ''' plot_controls.initialize() if show_tips: tips(plot_controls) @@ -29,4 +29,9 @@ def visualize(steps: list, plot_controls: PlotControls, show_tips: bool): return plot_data else: from fullcontrol.visualize.plotly import plot - return plot(plot_data, plot_controls) + fig = plot(plot_data, plot_controls) + + if plot_controls.return_fig == True: + return fig + else: + fig.show() From 50a756f538bdb40f280e3e335e402fa4bc000e02 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 09:03:16 +0100 Subject: [PATCH 03/12] Tentative update to to tutorial notebook. --- tutorials/plot_controls.ipynb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tutorials/plot_controls.ipynb b/tutorials/plot_controls.ipynb index 41545eb..0225485 100644 --- a/tutorials/plot_controls.ipynb +++ b/tutorials/plot_controls.ipynb @@ -16,6 +16,7 @@ "- `hide_axes` - True/False\n", "- `neat_for_publishing` - True/False (square format for consistent png creation)\n", "- `raw_data` - True/False (output data instead of creating a plot)\n", + "- `return_fig` - True/False (output figure object instead of showing plot immediatly)\n", "- `style` - options: 'tube'/'line' - preview 3D real-printed-volume lines or simple lines with non-representative widths\n", " - if `style == 'tube'`:\n", " - `tube_type` - options: 'flow'/'cylinders' - adjust how the plot transitions from line to line\n", @@ -313,7 +314,7 @@ "source": [ "#### edit the returned figure\n", "\n", - "`fc.transform` displays and returns a Plotly figure, which can be edited and shown again with updated formatting" + "`fc.transform` displays or returns a Plotly figure depending on `plot_controls.return_fig`. If `return_fig` is True it can be edited and shown again with updated formatting." ] }, { @@ -323,7 +324,9 @@ "outputs": [], "source": [ "print('Original figure:')\n", - "fig = fc.transform(steps, 'plot', show_tips=False)\n", + "plot_controls = fc.PlotControls(return_fig=True)\n", + "fig = fc.transform(steps, 'plot', plot_controls, show_tips=False)\n", + "fig.show()\n", "\n", "# Update the template and override the explicitly set background colors.\n", "fig.update_layout(\n", From c933544a77fddc30ba4054b6b09618513dbcc271 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 09:15:10 +0100 Subject: [PATCH 04/12] Tested changes in local copy of plot_controls tutorial, and updated colab tutorial to match. Should be ready for PR --- tutorials/colab/plot_controls_colab.ipynb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tutorials/colab/plot_controls_colab.ipynb b/tutorials/colab/plot_controls_colab.ipynb index 81696c2..eb9cd59 100644 --- a/tutorials/colab/plot_controls_colab.ipynb +++ b/tutorials/colab/plot_controls_colab.ipynb @@ -16,6 +16,7 @@ "- `hide_axes` - True/False\n", "- `neat_for_publishing` - True/False (square format for consistent png creation)\n", "- `raw_data` - True/False (output data instead of creating a plot)\n", + "- `return_fig` - True/False (output figure object instead of showing plot immediatly)\n", "- `style` - options: 'tube'/'line' - preview 3D real-printed-volume lines or simple lines with non-representative widths\n", " - if `style == 'tube'`:\n", " - `tube_type` - options: 'flow'/'cylinders' - adjust how the plot transitions from line to line\n", @@ -313,7 +314,7 @@ "source": [ "#### edit the returned figure\n", "\n", - "`fc.transform` displays and returns a Plotly figure, which can be edited and shown again with updated formatting" + "`fc.transform` displays or returns a Plotly figure depending on `plot_controls.return_fig`. If `return_fig` is True it can be edited and shown again with updated formatting." ] }, { @@ -323,7 +324,9 @@ "outputs": [], "source": [ "print('Original figure:')\n", - "fig = fc.transform(steps, 'plot', show_tips=False)\n", + "plot_controls = fc.PlotControls(return_fig=True)\n", + "fig = fc.transform(steps, 'plot', plot_controls, show_tips=False)\n", + "fig.show()\n", "\n", "# Update the template and override the explicitly set background colors.\n", "fig.update_layout(\n", From 553e298766695cb5ce07a0cc6b011e590d268976 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 10:40:03 +0100 Subject: [PATCH 05/12] Added first_print_point, last_print_point and find_extruder_state functions --- fullcontrol/extra_functions.py | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/fullcontrol/extra_functions.py b/fullcontrol/extra_functions.py index 7d09016..d4405f3 100644 --- a/fullcontrol/extra_functions.py +++ b/fullcontrol/extra_functions.py @@ -155,6 +155,82 @@ def last_point(steps: list, fully_defined: bool = True) -> Point: ''' return first_point(list(reversed(steps)), fully_defined) +def last_print_point(steps,extruder): + ''' + Returns last point in steps where the extruder is on, the initial extruder state should be set. + + Parameters: + - steps (list): a list of steps. + - extruder (bool): The initial state of the extruder. + + Returns: + - Point: The last Point in the list with extruder on. + + Raises: + - Exception if no point is found when extruder is on. + + ''' + last_point = None + for step in steps: + if type(step).__name__== "Extruder": + extruder = step.on + if type(step).__name__ == 'Point' and extruder: + last_point=step + + if last_point is None: + raise Exception('No point found in steps with extruder on') + + return last_point + +def first_print_point(steps,extruder): + ''' + Returns first point in steps where the extruder is on, the initial extruder state should be set. + + Parameters: + - steps (list): a list of steps. + - extruder (bool): The initial state of the extruder. + + Returns: + - Point: The first Point in the list with extruder on. + + Raises: + - Exception: if no point is found when extruder is on. + ''' + first_point = None + for step in steps: + if type(step).__name__== "Extruder": + extruder = step.on + if type(step).__name__ == 'Point' and extruder: + first_point=step + break + + if first_point is None: + raise Exception('No point found in steps with extruder on') + + return first_point + +def find_extruder_state(steps): + ''' + Finds final extruder state if any changes occur in steps. Can be used to find extruder state for use with first_print_point and last_print_point. + + Parameters: + - steps (list): a list of steps. + + Returns: + - extruder state: The final extruder state (True/False) + + Raises: + - Exception: if extruder state is not set in steps. + ''' + extruder = None + for step in steps: + if type(step).__name__== "Extruder": + extruder = step.on + + if extruder is None: + raise Exception('Extruder state not changed in steps.') + + return extruder def export_design(steps: list, filename: str): ''' From a6252741168dc7c44d616bcb0575abd00ab9e588 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 11:56:55 +0100 Subject: [PATCH 06/12] Added extra gcode controls to allow speed and geometry to always be printed in each gcode line irrespective of it being changed --- fullcontrol/gcode/controls.py | 4 ++++ fullcontrol/gcode/point.py | 20 ++++++++++++-------- fullcontrol/gcode/printer.py | 6 +++++- fullcontrol/gcode/state.py | 5 ++++- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/fullcontrol/gcode/controls.py b/fullcontrol/gcode/controls.py index 2fe4e62..fa780e3 100644 --- a/fullcontrol/gcode/controls.py +++ b/fullcontrol/gcode/controls.py @@ -12,11 +12,15 @@ class GcodeControls(BaseModel): initialization_data (Optional[dict]): Values passed for initialization_data overwrite the default initialization_data of the printer. Defaults to an empty dictionary. save_as (Optional[str]): The file name to save the gcode as. Defaults to None resulting in no file being saved. include_date (Optional[bool]): Whether to include the date in the filename. Defaults to True. + always_print_F (Optional[bool]): If True include speed in every gcode line irrespective of wether it changed. Defaults to False. + always_print_geometry (Optional[bool]): If True include x, y and z coordinate in every gcode line irrespective of wether each coordinate changed. Defaults to False. """ printer_name: Optional[str] = None initialization_data: Optional[dict] = {} # values passed for initialization_data overwrite the default initialization_data of the printer save_as: Optional[str] = None include_date: Optional[bool] = True + always_print_F: Optional[bool] = False + always_print_geometry: Optional[bool] = False def initialize(self): if self.printer_name is None: diff --git a/fullcontrol/gcode/point.py b/fullcontrol/gcode/point.py index fc03ed7..815288b 100644 --- a/fullcontrol/gcode/point.py +++ b/fullcontrol/gcode/point.py @@ -5,24 +5,28 @@ class Point(BasePoint): 'Extend generic class with gcode methods to convert the object to gcode' - def XYZ_gcode(self, p) -> float: + def XYZ_gcode(self, p,always_print) -> float: ''' Generate XYZ gcode string to move from a point p to this point. Args: p (Point): The point to move from. + always_print (bool): If True alway include all coordinates. Returns: str: The XYZ gcode string. ''' s = '' - if self.x != None and self.x != p.x: - s += f'X{self.x:.6f}'.rstrip('0').rstrip('.') + ' ' - if self.y != None and self.y != p.y: - s += f'Y{self.y:.6f}'.rstrip('0').rstrip('.') + ' ' - if self.z != None and self.z != p.z: - s += f'Z{self.z:.6f}'.rstrip('0').rstrip('.') + ' ' + if (self.x != None and self.x != p.x) or always_print == True: + x = self.x if self.x != None else p.x + s += f'X{x:.6f}'.rstrip('0').rstrip('.') + ' ' + if (self.y != None and self.y != p.y) or always_print == True: + y = self.y if self.y != None else p.y + s += f'Y{y:.6f}'.rstrip('0').rstrip('.') + ' ' + if (self.z != None and self.z != p.z) or always_print == True: + z = self.z if self.z != None else p.z + s += f'Z{z:.6f}'.rstrip('0').rstrip('.') + ' ' return s if s != '' else None def gcode(self, state): @@ -36,7 +40,7 @@ def gcode(self, state): str: The generated line of gcode. ''' - XYZ_str = self.XYZ_gcode(state.point) + XYZ_str = self.XYZ_gcode(state.point,state.printer.always_print_geometry) if XYZ_str != None: # only write a line of gcode if movement occurs G_str = 'G1 ' if state.extruder.on or state.extruder.travel_format == "G1_E0" else 'G0 ' F_str = state.printer.f_gcode(state) diff --git a/fullcontrol/gcode/printer.py b/fullcontrol/gcode/printer.py index 8a97241..3bff5ed 100644 --- a/fullcontrol/gcode/printer.py +++ b/fullcontrol/gcode/printer.py @@ -11,10 +11,14 @@ class Printer(BasePrinter): command_list (Optional[dict]): A dictionary containing the printer's command list. new_command (Optional[dict]): A dictionary containing a new command to be added to the command list. speed_changed (Optional[bool]): A flag indicating whether the print speed or travel speed has changed. + always_print_F (Optional[bool]): If True include speed in every gcode line irrespective of wether it changed. Defaults to False. + always_print_geometry (Optional[bool]): If True include x, y and z coordinate in every gcode line irrespective of wether each coordinate changed. Defaults to False. ''' command_list: Optional[dict] = None new_command: Optional[dict] = None speed_changed: Optional[bool] = None + always_print_F: Optional[bool] = None + always_print_geometry: Optional[bool] = None def f_gcode(self, state): """ @@ -26,7 +30,7 @@ def f_gcode(self, state): Returns: - The G-code string for the feedrate (F) based on the current state. """ - if self.speed_changed == True: + if self.speed_changed == True or self.always_print_F == True: return f'F{self.print_speed if state.extruder.on else self.travel_speed:.1f}'.rstrip('0').rstrip('.') + ' ' else: return '' diff --git a/fullcontrol/gcode/state.py b/fullcontrol/gcode/state.py index c97eabd..33004a6 100644 --- a/fullcontrol/gcode/state.py +++ b/fullcontrol/gcode/state.py @@ -73,7 +73,10 @@ def __init__(self, steps: list, gcode_controls: GcodeControls): command_list=initialization_data['printer_command_list'], print_speed=initialization_data['print_speed'], travel_speed=initialization_data['travel_speed'], - speed_changed=True) + speed_changed=True, + always_print_F=gcode_controls.always_print_F, + always_print_geometry=gcode_controls.always_print_geometry, + ) self.extrusion_geometry = ExtrusionGeometry( area_model=initialization_data['area_model'], From d21199a4f3fee02717b43a258ea2266645aa4d28 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 12:20:33 +0100 Subject: [PATCH 07/12] Fixed first_print_point to return the point immediatly before the extruder being turned on if present --- fullcontrol/extra_functions.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fullcontrol/extra_functions.py b/fullcontrol/extra_functions.py index d4405f3..b42bdee 100644 --- a/fullcontrol/extra_functions.py +++ b/fullcontrol/extra_functions.py @@ -196,14 +196,17 @@ def first_print_point(steps,extruder): Raises: - Exception: if no point is found when extruder is on. ''' + point_prospect = None # The first point needs to be the point immediatly before the extruder is turned on, so the latest point needs to be accesible. first_point = None for step in steps: + if type(step).__name__ == 'Point': + point_prospect=step if type(step).__name__== "Extruder": - extruder = step.on - if type(step).__name__ == 'Point' and extruder: - first_point=step - break - + extruder = step.on + if extruder and point_prospect is not None: + first_point = point_prospect + break + if first_point is None: raise Exception('No point found in steps with extruder on') From 6e3439ad3883b9e7e28b012174da72b8fde14af7 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 12:29:05 +0100 Subject: [PATCH 08/12] Added new functions to common so they can be used --- fullcontrol/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fullcontrol/common.py b/fullcontrol/common.py index 4a8c531..b463e5f 100644 --- a/fullcontrol/common.py +++ b/fullcontrol/common.py @@ -3,5 +3,5 @@ from fullcontrol.auxilliary_components import Fan, Hotend, Buildplate from fullcontrol.point import Point from fullcontrol.printer import Printer -from fullcontrol.extra_functions import points_only, relative_point, flatten, linspace, first_point, last_point, export_design, import_design +from fullcontrol.extra_functions import points_only, relative_point, flatten, linspace, first_point, last_point, first_print_point, last_print_point, find_extruder_state, export_design, import_design from fullcontrol.check import check, fix, check_points \ No newline at end of file From a400f9e630c783ac3a7c7a53cd00ca35ee45df68 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 12:39:41 +0100 Subject: [PATCH 09/12] Added new functions to the other common to allow them to be used --- fullcontrol/combinations/gcode_and_visualize/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fullcontrol/combinations/gcode_and_visualize/common.py b/fullcontrol/combinations/gcode_and_visualize/common.py index 01f9b67..0d82d84 100644 --- a/fullcontrol/combinations/gcode_and_visualize/common.py +++ b/fullcontrol/combinations/gcode_and_visualize/common.py @@ -6,7 +6,7 @@ # import functions and classes that will be accessible to the user from .classes import * from fullcontrol.common import fix -from fullcontrol.common import check, flatten, linspace, export_design, import_design, points_only, relative_point, first_point, last_point +from fullcontrol.common import check, flatten, linspace, export_design, import_design, points_only, relative_point, first_point, last_point, first_print_point, last_print_point, find_extruder_state from fullcontrol.geometry import * from fullcontrol.visualize.bounding_box import BoundingBox From 4b443ea5e9649d4b7e69798cf41c0bfe1835bfcb Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 12:51:15 +0100 Subject: [PATCH 10/12] Updated other functions to include first_print_point and last_print_point --- tutorials/colab/other_functions_colab.ipynb | 24 +++++++++++++++++++++ tutorials/other_functions.ipynb | 24 +++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/tutorials/colab/other_functions_colab.ipynb b/tutorials/colab/other_functions_colab.ipynb index 0093e1d..6518a2a 100644 --- a/tutorials/colab/other_functions_colab.ipynb +++ b/tutorials/colab/other_functions_colab.ipynb @@ -205,6 +205,30 @@ "print(\"last point in the design (fully defined): \" + str(fc.last_point(steps, fully_defined=True)))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### find the first or last print point in a ***design*** with fc.first_print_point() and fc.last_print_point() \n", + "\n", + "these functions find the first or last point objects in the design with the extruder being on. It hence disregards travel moves." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "steps = [fc.Extruder(on=False),fc.Point(x=0,y=1,z=0),fc.Point(x=0,y=0,z=0),fc.Extruder(on=True),fc.Point(x=1,y=0,z=0),fc.Extruder(on=False),fc.Point(x=1,y=0,z=1)]\n", + "\n", + "print(\"first step in the design: \" + str(type(steps[0]).__name__))\n", + "print(\"first point in the design: \" + str(fc.first_point(steps)))\n", + "print(\"first print point in the design: \" + str(fc.first_print_point(steps,extruder=False))) # In this example the initial step defines the extruder so setting the extruder to True or False makes no difference.\n", + "print(\"last print point in the design: \" + str(fc.last_print_point(steps,extruder=False)))\n", + "print(\"last point in the design: \" + str(fc.last_point(steps)))" + ] + }, { "attachments": {}, "cell_type": "markdown", diff --git a/tutorials/other_functions.ipynb b/tutorials/other_functions.ipynb index 6d46a52..997b6f0 100644 --- a/tutorials/other_functions.ipynb +++ b/tutorials/other_functions.ipynb @@ -205,6 +205,30 @@ "print(\"last point in the design (fully defined): \" + str(fc.last_point(steps, fully_defined=True)))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### find the first or last print point in a ***design*** with fc.first_print_point() and fc.last_print_point() \n", + "\n", + "these functions find the first or last point objects in the design with the extruder being on. It hence disregards travel moves." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "steps = [fc.Extruder(on=False),fc.Point(x=0,y=1,z=0),fc.Point(x=0,y=0,z=0),fc.Extruder(on=True),fc.Point(x=1,y=0,z=0),fc.Extruder(on=False),fc.Point(x=1,y=0,z=1)]\n", + "\n", + "print(\"first step in the design: \" + str(type(steps[0]).__name__))\n", + "print(\"first point in the design: \" + str(fc.first_point(steps)))\n", + "print(\"first print point in the design: \" + str(fc.first_print_point(steps,extruder=False))) # In this example the initial step defines the extruder so setting the extruder to True or False makes no difference.\n", + "print(\"last print point in the design: \" + str(fc.last_print_point(steps,extruder=False)))\n", + "print(\"last point in the design: \" + str(fc.last_point(steps)))" + ] + }, { "attachments": {}, "cell_type": "markdown", From 9e32f09d56c84f9972bd68332aecdd91223b64e2 Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 13:06:35 +0100 Subject: [PATCH 11/12] Tentative update to gcode_controls tutorial --- tutorials/gcode_controls.ipynb | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tutorials/gcode_controls.ipynb b/tutorials/gcode_controls.ipynb index 00069b5..5dbd239 100644 --- a/tutorials/gcode_controls.ipynb +++ b/tutorials/gcode_controls.ipynb @@ -14,6 +14,8 @@ "- `printer_name` - used to choose which printer the gcode should be formatted for\n", " - a selection of printers are built in, which is expected to be extended. documentation for adding new printers will be provided in the future\n", "- `initialization_data` - used to change the initial print conditions/settings that are established before the steps in the ***design*** are evaluated\n", + "- `always_print_F` - used to always include speed in every gcode line irrespective of wether it changed. Defaults to False.\n", + "- `always_print_geometry` - used to always include x, y and z coordinate in every gcode line irrespective of wether each coordinate changed. Defaults to False.\n", "\n", "<*this document is a jupyter notebook - if they're new to you, check out how they work:\n", "[link](https://www.google.com/search?q=ipynb+tutorial),\n", @@ -348,6 +350,49 @@ "steps = starting_procedure_steps + design_steps\n", "print(fc.transform(steps, 'gcode', gcode_controls))" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Always include speed and geometry" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "initial_settings = {\n", + " \"extrusion_width\": 0.4,\n", + " \"extrusion_height\": 0.2,\n", + " \"primer\": \"no_primer\",\n", + " \"print_speed\": 1000,\n", + "}\n", + "gcode_controls = fc.GcodeControls(initialization_data=initial_settings)\n", + "gcode_controls_F = fc.GcodeControls(always_print_F=True,initialization_data=initial_settings)\n", + "gcode_controls_geometry = fc.GcodeControls(always_print_geometry=True,initialization_data=initial_settings)\n", + "gcode_controls_both = fc.GcodeControls(always_print_F=True,always_print_geometry=True,initialization_data=initial_settings)\n", + "steps = [fc.Printer(print_speed=1000),fc.Point(x=0,y=0,z=0),fc.Point(y=1),fc.Point(x=1),fc.Printer(print_speed=2000),fc.Point(y=0),fc.Point(x=0)]\n", + "\n", + "print(\"Conventional gcode\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls))\n", + "print(\"\")\n", + "\n", + "print(\"With speed always on\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_F))\n", + "print(\"\")\n", + "\n", + "print(\"With geometry always on\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_geometry))\n", + "print(\"\")\n", + "\n", + "print(\"With both always on\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_both))\n", + "print(\"\")\n", + "\n" + ] } ], "metadata": { From 36525101512db3388aab154e4534f1890ecd368e Mon Sep 17 00:00:00 2001 From: Awolstrup Date: Wed, 30 Sep 2026 13:17:17 +0100 Subject: [PATCH 12/12] Confirmed the additions to gcode controls work, and updated the tutorials --- tutorials/colab/gcode_controls_colab.ipynb | 44 ++++++++++++++++++++++ tutorials/gcode_controls.ipynb | 31 ++++++++------- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/tutorials/colab/gcode_controls_colab.ipynb b/tutorials/colab/gcode_controls_colab.ipynb index 41bb1ce..203a644 100644 --- a/tutorials/colab/gcode_controls_colab.ipynb +++ b/tutorials/colab/gcode_controls_colab.ipynb @@ -14,6 +14,8 @@ "- `printer_name` - used to choose which printer the gcode should be formatted for\n", " - a selection of printers are built in, which is expected to be extended. documentation for adding new printers will be provided in the future\n", "- `initialization_data` - used to change the initial print conditions/settings that are established before the steps in the ***design*** are evaluated\n", + "- `always_print_F` - used to always include speed in every gcode line irrespective of wether it changed. Defaults to False.\n", + "- `always_print_geometry` - used to always include x, y and z coordinate in every gcode line irrespective of wether each coordinate changed. Defaults to False.\n", "\n", "<*this document is a jupyter notebook - if they're new to you, check out how they work:\n", "[link](https://www.google.com/search?q=ipynb+tutorial),\n", @@ -348,6 +350,48 @@ "steps = starting_procedure_steps + design_steps\n", "print(fc.transform(steps, 'gcode', gcode_controls))" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Always include speed and geometry" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "initial_settings = {\n", + " \"extrusion_width\": 0.4,\n", + " \"extrusion_height\": 0.2,\n", + " \"primer\": \"no_primer\",\n", + " \"print_speed\": 1000,\n", + "}\n", + "gcode_controls = fc.GcodeControls(initialization_data=initial_settings,printer_name='generic')\n", + "gcode_controls_F = fc.GcodeControls(always_print_F=True,initialization_data=initial_settings,printer_name='generic')\n", + "gcode_controls_geometry = fc.GcodeControls(always_print_geometry=True,initialization_data=initial_settings,printer_name='generic')\n", + "gcode_controls_both = fc.GcodeControls(always_print_F=True,always_print_geometry=True,initialization_data=initial_settings,printer_name='generic')\n", + "steps = [fc.Extruder(on=True),fc.Printer(print_speed=1000),fc.Point(x=0,y=0,z=0),fc.Point(y=1),fc.Point(x=1),fc.Printer(print_speed=2000),fc.Point(y=0),fc.Point(x=0)]\n", + "\n", + "print(\"Conventional gcode:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls)[175:]) # The initial 175 characters are a comment, and are removed for clarity\n", + "print(\"\")\n", + "\n", + "print(\"With speed always on:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_F)[175:])\n", + "print(\"\")\n", + "\n", + "print(\"With geometry always on:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_geometry)[175:])\n", + "print(\"\")\n", + "\n", + "print(\"With both always on:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_both)[175:])\n", + "print(\"\")" + ] } ], "metadata": { diff --git a/tutorials/gcode_controls.ipynb b/tutorials/gcode_controls.ipynb index 5dbd239..38fd06b 100644 --- a/tutorials/gcode_controls.ipynb +++ b/tutorials/gcode_controls.ipynb @@ -370,28 +370,27 @@ " \"primer\": \"no_primer\",\n", " \"print_speed\": 1000,\n", "}\n", - "gcode_controls = fc.GcodeControls(initialization_data=initial_settings)\n", - "gcode_controls_F = fc.GcodeControls(always_print_F=True,initialization_data=initial_settings)\n", - "gcode_controls_geometry = fc.GcodeControls(always_print_geometry=True,initialization_data=initial_settings)\n", - "gcode_controls_both = fc.GcodeControls(always_print_F=True,always_print_geometry=True,initialization_data=initial_settings)\n", - "steps = [fc.Printer(print_speed=1000),fc.Point(x=0,y=0,z=0),fc.Point(y=1),fc.Point(x=1),fc.Printer(print_speed=2000),fc.Point(y=0),fc.Point(x=0)]\n", - "\n", - "print(\"Conventional gcode\")\n", - "print(fc.transform(steps, 'gcode', gcode_controls))\n", + "gcode_controls = fc.GcodeControls(initialization_data=initial_settings,printer_name='generic')\n", + "gcode_controls_F = fc.GcodeControls(always_print_F=True,initialization_data=initial_settings,printer_name='generic')\n", + "gcode_controls_geometry = fc.GcodeControls(always_print_geometry=True,initialization_data=initial_settings,printer_name='generic')\n", + "gcode_controls_both = fc.GcodeControls(always_print_F=True,always_print_geometry=True,initialization_data=initial_settings,printer_name='generic')\n", + "steps = [fc.Extruder(on=True),fc.Printer(print_speed=1000),fc.Point(x=0,y=0,z=0),fc.Point(y=1),fc.Point(x=1),fc.Printer(print_speed=2000),fc.Point(y=0),fc.Point(x=0)]\n", + "\n", + "print(\"Conventional gcode:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls)[175:]) # The initial 175 characters are a comment, and are removed for clarity\n", "print(\"\")\n", "\n", - "print(\"With speed always on\")\n", - "print(fc.transform(steps, 'gcode', gcode_controls_F))\n", + "print(\"With speed always on:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_F)[175:])\n", "print(\"\")\n", "\n", - "print(\"With geometry always on\")\n", - "print(fc.transform(steps, 'gcode', gcode_controls_geometry))\n", + "print(\"With geometry always on:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_geometry)[175:])\n", "print(\"\")\n", "\n", - "print(\"With both always on\")\n", - "print(fc.transform(steps, 'gcode', gcode_controls_both))\n", - "print(\"\")\n", - "\n" + "print(\"With both always on:\")\n", + "print(fc.transform(steps, 'gcode', gcode_controls_both)[175:])\n", + "print(\"\")" ] } ],