Source code for gcoordinator.path_generator

import os
import pickle
import json
from typing import Any
import numpy as np
from gcoordinator.kinematics.kin_bed_rotate  import BedRotate
from gcoordinator.kinematics.kin_cartesian   import Cartesian
from gcoordinator.kinematics.kin_bed_tilt_bc import BedTiltBC
from gcoordinator.kinematics.kin_nozzle_tilt import NozzleTilt
from gcoordinator.settings                   import template_settings


[docs] class Path: """ A class representing a path in 3D space. Attributes: ----------- x : numpy.ndarray The x-coordinates of the path points. y : numpy.ndarray The y-coordinates of the path points. z : numpy.ndarray The z-coordinates of the path points. rot : numpy.ndarray The rotation at each point in the path, in radians. tilt : numpy.ndarray The tilt at each point in the path, in radians. kinematics : str The kinematics of the printer. One of 'Cartesian', 'BedRotate', 'BedTiltBC', or 'NozzleTilt'. coords : numpy.ndarray A 2D array of shape (n_points, 3) containing the (x, y, z) coordinates of the path points. norms : numpy.ndarray A 2D array of shape (n_points, 3) containing the (x, y, z) components of the normals at each point in the path. center : numpy.ndarray The center of the path, calculated as the mean of the path points. start_coord : numpy.ndarray The coordinates of the first point in the path. end_coord : numpy.ndarray The coordinates of the last point in the path. nozzle_diameter : float The diameter of the printer nozzle, in millimeters. filament_diameter : float The diameter of the printer filament, in millimeters. layer_height : float The height of each printed layer, in millimeters. print_speed : float The speed at which the printer extrudes filament, in millimeters per second. travel_speed : float The speed at which the printer moves between points, in millimeters per second. x_origin : float The x-coordinate of the origin of the printer's coordinate system, in millimeters. y_origin : float The y-coordinate of the origin of the printer's coordinate system, in millimeters. fan_speed : float The speed of the printer's cooling fan, as a percentage of its maximum speed. nozzle_temperature : float The temperature of the printer nozzle, in degrees Celsius. bed_temperature : float The temperature of the printer bed, in degrees Celsius. retraction : bool Whether to retract the filament between moves. retraction_distance : float The distance by which to retract the filament, in millimeters. unretraction_distance : float The distance by which to unretract the filament, in millimeters. z_hop : bool Whether to perform a Z-hop between moves. z_hop_distance : float The distance by which to Z-hop, in millimeters. extrusion_multiplier : float A multiplier for the amount of filament extruded, used to adjust for filament diameter variations. segment_extrusion_multiplier : numpy.ndarray or None Per-segment multiplier for filament extrusion. An array of the same length as x and y. For segment i (from point i to i+1), the value at index i is used. When both extrusion_multiplier and segment_extrusion_multiplier are specified, segment_extrusion_multiplier takes precedence. segment_print_speed : numpy.ndarray or None Per-segment print speed. An array of the same length as x and y. For segment i (from point i to i+1), the value at index i is used. When both print_speed and segment_print_speed are specified, segment_print_speed takes precedence. Methods: -------- apply_default_settings() Applies the default settings to the object. apply_optional_settings() Applies the optional settings to the object. """ def __init__(self, x, y, z, rot=None, tilt=None, **kwargs): try: self.settings_path = '.temp_config.json' with open(self.settings_path, 'r') as f: self.settings = json.load(f) except: self.settings = template_settings # gcoordinator/settings.py self.kinematics = self.settings['Hardware']['kinematics'] self.x = np.array(x) self.y = np.array(y) self.z = np.array(z) if tilt is None: self.tilt = np.full_like(x, 0) else: self.tilt = np.array(tilt) if rot is None: self.rot = np.full_like(x, 0) else: self.rot = np.array(rot) self.coords = np.column_stack([self.x, self.y, self.z]) self.norms = np.array([(0, 0, 1) for _ in range(len(self.coords))]) self.center = np.array([np.mean(self.x), np.mean(self.y), np.mean(self.z)]) self.start_coord = self.coords[0] self.end_coord = self.coords[-1] self.before_gcode = None self.after_gcode = None # recalculate the coordinates and the norms according to the kinematics if self.kinematics == 'Cartesian': Cartesian.update_attrs(self) elif self.kinematics == 'BedRotate': BedRotate.update_attrs(self) elif self.kinematics == 'BedTiltBC': BedTiltBC.update_attrs(self) elif self.kinematics == 'NozzleTilt': NozzleTilt.update_attrs(self) # apply default settings to the object self.apply_default_settings() # apply optional settings to the object self.optional_settings = kwargs self.apply_optional_settings()
[docs] def apply_default_settings(self): # When generating G-code, if the attribute of Path is None, # the default value will be used. # During the instantiation of the Path object, the default value is unknown, # so it is set to None. self.nozzle_diameter = None self.filament_diameter = None self.layer_height = None self.print_speed = None self.travel_speed = None self.x_origin = None self.y_origin = None self.fan_speed = None self.nozzle_temperature = None self.bed_temperature = None self.retraction = None self.retraction_distance = None self.unretraction_distance = None self.z_hop = None self.z_hop_distance = None self.extrusion_multiplier = None self.segment_extrusion_multiplier = None self.segment_print_speed = None self.travel_path = None
[docs] def apply_optional_settings(self): """ Applies optional settings to the current instance of the Path class. This method iterates over the optional_settings dictionary and sets each key-value pair as an attribute of the current instance of the PathGenerator class. Args: None Returns: None """ for key, value in self.optional_settings.items(): setattr(self, key, value)
[docs] class PathList: """ A class representing a list of paths. This class has the same attributes of Path class. The attributes are applied to all paths in the PathList. Attributes: paths (list): A list of Path objects. all attributes of Path class Methods: __init__(self, paths): Initializes a PathList object with a list of Path objects. __setattr__(self, name, value): Sets an attribute to all paths in the PathList. sort_paths(self): Sorts the paths in the PathList object in order of proximity to the previous path's end point. """
[docs] def __init__(self, paths): self.paths = paths self.index = 0 # index for __next__ if len(paths) != 0: self.sort_paths()
[docs] def __setattr__(self, name, value): """ Sets an attribute to all paths in the PathList. Args: name (str): The name of the attribute to set. value (any): The value to set the attribute to. Returns: None """ if name == 'paths': self.__dict__[name] = value return # set attribute to all paths in the PathList for path in self.paths: if hasattr(path, name): setattr(path, name, value) else: self.__dict__[name] = value
def __iter__(self): return self def __next__(self): if self.index < len(self.paths): current_path = self.paths[self.index] self.index += 1 return current_path else: raise StopIteration()
[docs] def sort_paths(self): """ Sorts the paths in the PathList object in order of proximity to the previous path's end point. Args: None Returns: None """ sorted_paths = [] remaining_paths = self.paths.copy() # Extract first path and add to sorted list current_path = remaining_paths.pop(0) sorted_paths.append(current_path) while remaining_paths: nearest_index = None min_distance = float('inf') # Find the path with the closest starting point among unsorted paths for i, path in enumerate(remaining_paths): distance = np.linalg.norm(current_path.end_coord - path.start_coord) if distance < min_distance: min_distance = distance nearest_index = i # Retrieve the closest path and add it to the sorted list current_path = remaining_paths.pop(nearest_index) sorted_paths.append(current_path) self.paths = sorted_paths
[docs] def flatten_path_list(full_object): """ the full_object(list) is composed of Path and PathList. when calcuate, PathList nedds to be flatten. this function makes all elements in full_object to Path. args : list of Path and PathList returns : list of Path """ flattened_paths = [] for item in full_object: if isinstance(item, PathList): flattened_paths.extend(flatten_path_list(item.paths)) elif isinstance(item, Path): flattened_paths.append(item) return flattened_paths