diff options
Diffstat (limited to 'GcodeProcessorLib/gcode_position.cpp')
-rw-r--r-- | GcodeProcessorLib/gcode_position.cpp | 1418 |
1 files changed, 1418 insertions, 0 deletions
diff --git a/GcodeProcessorLib/gcode_position.cpp b/GcodeProcessorLib/gcode_position.cpp new file mode 100644 index 0000000..3fc661f --- /dev/null +++ b/GcodeProcessorLib/gcode_position.cpp @@ -0,0 +1,1418 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Gcode Processor Library +// +// Tools for parsing gcode and calculating printer state from parsed gcode commands. +// +// Copyright(C) 2020 - Brad Hochgesang +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// This program is free software : you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the +// GNU Affero General Public License for more details. +// +// +// You can contact the author at the following email address: +// FormerLurker@pm.me +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "gcode_position.h" +#include "utilities.h" +#include <algorithm> +#include <iterator> +#include <math.h> +gcode_position_args::gcode_position_args(const gcode_position_args &pos_args) +{ + position_buffer_size = pos_args.position_buffer_size; + shared_extruder = pos_args.shared_extruder; + autodetect_position = pos_args.autodetect_position; + is_circular_bed = pos_args.is_circular_bed; + home_x = pos_args.home_x; + home_y = pos_args.home_y; + home_z = pos_args.home_z; + home_x_none = pos_args.home_x_none; + home_y_none = pos_args.home_y_none; + home_z_none = pos_args.home_z_none; + + priming_height = pos_args.priming_height; + minimum_layer_height = pos_args.minimum_layer_height; + height_increment = pos_args.height_increment; + g90_influences_extruder = pos_args.g90_influences_extruder; + xyz_axis_default_mode = pos_args.xyz_axis_default_mode; + e_axis_default_mode = pos_args.e_axis_default_mode; + units_default = pos_args.units_default; + is_bound_ = pos_args.is_bound_; + x_min = pos_args.x_min; + x_max = pos_args.x_max; + y_min = pos_args.y_min; + y_max = pos_args.y_max; + z_min = pos_args.z_min; + z_max = pos_args.z_max; + snapshot_x_min = pos_args.snapshot_x_min; + snapshot_x_max = pos_args.snapshot_x_max; + snapshot_y_min = pos_args.snapshot_y_min; + snapshot_y_max = pos_args.snapshot_y_max; + snapshot_z_min = pos_args.snapshot_z_min; + snapshot_z_max = pos_args.snapshot_z_max; + + default_extruder = pos_args.default_extruder; + zero_based_extruder = pos_args.zero_based_extruder; + num_extruders = pos_args.num_extruders; + retraction_lengths = NULL; + z_lift_heights = NULL; + x_firmware_offsets = NULL; + y_firmware_offsets = NULL; + set_num_extruders(pos_args.num_extruders); + + for (int index = 0; index < pos_args.num_extruders; index++) + { + retraction_lengths[index] = pos_args.retraction_lengths[index]; + z_lift_heights[index] = pos_args.z_lift_heights[index]; + if (!pos_args.shared_extruder) + { + x_firmware_offsets[index] = pos_args.x_firmware_offsets[index]; + y_firmware_offsets[index] = pos_args.y_firmware_offsets[index]; + } + else + { + x_firmware_offsets[index] = 0; + y_firmware_offsets[index] = 0; + } + } + std::vector<std::string> location_detection_commands; // Final list of location detection commands +} + +gcode_position_args& gcode_position_args::operator=(const gcode_position_args& pos_args) +{ + position_buffer_size = pos_args.position_buffer_size; + shared_extruder = pos_args.shared_extruder; + autodetect_position = pos_args.autodetect_position; + is_circular_bed = pos_args.is_circular_bed; + home_x = pos_args.home_x; + home_y = pos_args.home_y; + home_z = pos_args.home_z; + home_x_none = pos_args.home_x_none; + home_y_none = pos_args.home_y_none; + home_z_none = pos_args.home_z_none; + + priming_height = pos_args.priming_height; + minimum_layer_height = pos_args.minimum_layer_height; + height_increment = pos_args.height_increment; + g90_influences_extruder = pos_args.g90_influences_extruder; + xyz_axis_default_mode = pos_args.xyz_axis_default_mode; + e_axis_default_mode = pos_args.e_axis_default_mode; + units_default = pos_args.units_default; + is_bound_ = pos_args.is_bound_; + x_min = pos_args.x_min; + x_max = pos_args.x_max; + y_min = pos_args.y_min; + y_max = pos_args.y_max; + z_min = pos_args.z_min; + z_max = pos_args.z_max; + snapshot_x_min = pos_args.snapshot_x_min; + snapshot_x_max = pos_args.snapshot_x_max; + snapshot_y_min = pos_args.snapshot_y_min; + snapshot_y_max = pos_args.snapshot_y_max; + snapshot_z_min = pos_args.snapshot_z_min; + snapshot_z_max = pos_args.snapshot_z_max; + + default_extruder = pos_args.default_extruder; + zero_based_extruder = pos_args.zero_based_extruder; + num_extruders = pos_args.num_extruders; + delete_retraction_lengths(); + delete_x_firmware_offsets(); + delete_y_firmware_offsets(); + delete_z_lift_heights(); + set_num_extruders(pos_args.num_extruders); + // copy extruder specific members + for(int index=0; index < pos_args.num_extruders; index++) + { + retraction_lengths[index] = pos_args.retraction_lengths[index]; + z_lift_heights[index] = pos_args.z_lift_heights[index]; + if (!pos_args.shared_extruder) + { + x_firmware_offsets[index] = pos_args.x_firmware_offsets[index]; + y_firmware_offsets[index] = pos_args.y_firmware_offsets[index]; + } + else + { + x_firmware_offsets[index] = 0; + y_firmware_offsets[index] = 0; + } + } + std::vector<std::string> location_detection_commands; // Final list of location detection commands + return *this; +} + +void gcode_position_args::set_num_extruders(int num_extruders_) +{ + delete_retraction_lengths(); + delete_z_lift_heights(); + delete_x_firmware_offsets(); + delete_y_firmware_offsets(); + num_extruders = num_extruders_; + + retraction_lengths = new double[num_extruders_]; + z_lift_heights = new double[num_extruders_]; + x_firmware_offsets = new double[num_extruders_]; + y_firmware_offsets = new double[num_extruders_]; + // initialize arrays + for (int index=0; index < num_extruders; index++) + { + retraction_lengths[index] = 0.0; + z_lift_heights[index] = 0.0; + x_firmware_offsets[index] = 0.0; + y_firmware_offsets[index] = 0.0; + } +} + +void gcode_position_args::delete_retraction_lengths() +{ + if (retraction_lengths != NULL) + { + delete[] retraction_lengths; + retraction_lengths = NULL; + } +} + +void gcode_position_args::delete_z_lift_heights() +{ + if (z_lift_heights != NULL) + { + delete[] z_lift_heights; + z_lift_heights = NULL; + } +} + +void gcode_position_args::delete_x_firmware_offsets() +{ + if (x_firmware_offsets != NULL) + { + delete[] x_firmware_offsets; + x_firmware_offsets = NULL; + } +} + +void gcode_position_args::delete_y_firmware_offsets() +{ + if (y_firmware_offsets != NULL) + { + delete[] y_firmware_offsets; + y_firmware_offsets = NULL; + } +} + +gcode_position::gcode_position() +{ + position_buffer_size_ = 50; + positions_ = new position[position_buffer_size_]; + autodetect_position_ = false; + home_x_ = 0; + home_y_ = 0; + home_z_ = 0; + home_x_none_ = true; + home_y_none_ = true; + home_z_none_ = true; + retraction_lengths_ = NULL; + z_lift_heights_ = NULL; + shared_extruder_ = false; + set_num_extruders(0); + zero_based_extruder_ = true; + priming_height_ = 0; + minimum_layer_height_ = 0; + height_increment_ = 0; + g90_influences_extruder_ = false; + e_axis_default_mode_ = "absolute"; + xyz_axis_default_mode_ = "absolute"; + units_default_ = "millimeters"; + gcode_functions_ = get_gcode_functions(); + + is_bound_ = false; + snapshot_x_min_ = 0; + snapshot_x_max_ = 0; + snapshot_y_min_ = 0; + snapshot_y_max_ = 0; + snapshot_z_min_ = 0; + snapshot_z_max_ = 0; + + x_min_ = 0; + x_max_ = 0; + y_min_ = 0; + y_max_ = 0; + z_min_ = 0; + z_max_ = 0; + is_circular_bed_ = false; + + cur_pos_ = -1; + num_pos_ = 0; + for(int index = 0; index < position_buffer_size_; index ++) + { + position initial_pos(num_extruders_); + initial_pos.set_xyz_axis_mode(xyz_axis_default_mode_); + initial_pos.set_e_axis_mode(e_axis_default_mode_); + initial_pos.set_units_default(units_default_); + add_position(initial_pos); + } + num_pos_ = 0; +} + +gcode_position::gcode_position(gcode_position_args args) +{ + position_buffer_size_ = args.position_buffer_size; + positions_ = new position[args.position_buffer_size] ; + autodetect_position_ = args.autodetect_position; + home_x_ = args.home_x; + home_y_ = args.home_y; + home_z_ = args.home_z; + home_x_none_ = args.home_x_none; + home_y_none_ = args.home_y_none; + home_z_none_ = args.home_z_none; + retraction_lengths_ = NULL; + z_lift_heights_ = NULL; + // Configure Extruders + shared_extruder_ = args.shared_extruder; + set_num_extruders(args.num_extruders); + zero_based_extruder_ = args.zero_based_extruder; + // Set the current extruder to the default extruder (0 based) + int current_extruder = args.default_extruder; + // make sure our current extruder is between 0 and num_extruders - 1 + if (current_extruder < 0) + { + current_extruder = 0; + } + else if (current_extruder > args.num_extruders - 1) + { + current_extruder = args.num_extruders - 1; + } + + // copy the retraction lengths array + for (int index=0; index < args.num_extruders; index++) + { + retraction_lengths_[index] = args.retraction_lengths[index]; + } + // Copy the z_lift_heights array from the arguments + for (int index = 0; index < args.num_extruders; index++) + { + z_lift_heights_[index] = args.z_lift_heights[index]; + } + // Copy the firmware offsets + for (int index = 0; index < args.num_extruders; index++) + { + retraction_lengths_[index] = args.retraction_lengths[index]; + } + + priming_height_ = args.priming_height; + minimum_layer_height_ = args.minimum_layer_height; + height_increment_ = args.height_increment; + g90_influences_extruder_ = args.g90_influences_extruder; + e_axis_default_mode_ = args.e_axis_default_mode; + xyz_axis_default_mode_ = args.xyz_axis_default_mode; + units_default_ = args.units_default; + gcode_functions_ = get_gcode_functions(); + + is_bound_ = args.is_bound_; + snapshot_x_min_ = args.snapshot_x_min; + snapshot_x_max_ = args.snapshot_x_max; + snapshot_y_min_ = args.snapshot_y_min; + snapshot_y_max_ = args.snapshot_y_max; + snapshot_z_min_ = args.snapshot_z_min; + snapshot_z_max_ = args.snapshot_z_max; + + x_min_ = args.x_min; + x_max_ = args.x_max; + y_min_ = args.y_min; + y_max_ = args.y_max; + z_min_ = args.z_min; + z_max_ = args.z_max; + + is_circular_bed_ = args.is_circular_bed; + + cur_pos_ = -1; + num_pos_ = 0; + num_extruders_ = args.num_extruders; + + // Configure the initial position + position initial_pos(num_extruders_); + initial_pos.set_xyz_axis_mode(xyz_axis_default_mode_); + initial_pos.set_e_axis_mode(e_axis_default_mode_); + initial_pos.set_units_default(units_default_); + initial_pos.current_tool = current_extruder; + for (int index = 0; index < args.num_extruders; index++) + { + initial_pos.p_extruders[index].x_firmware_offset = args.x_firmware_offsets[index]; + initial_pos.p_extruders[index].y_firmware_offset = args.y_firmware_offsets[index]; + } + + for (int index = 0; index < position_buffer_size_; index++) + { + + add_position(initial_pos); + } + num_pos_ = 0; +} + +gcode_position::gcode_position(const gcode_position &source) +{ + // Private copy constructor - you can't copy this class +} + +gcode_position::~gcode_position() +{ + if (positions_ != NULL) + { + delete [] positions_; + positions_ = NULL; + } + delete_retraction_lengths_(); + delete_z_lift_heights_(); +} + +void gcode_position::set_num_extruders(int num_extruders) +{ + delete_retraction_lengths_(); + delete_z_lift_heights_(); + if (shared_extruder_) + { + num_extruders_ = 1; + } + else + { + num_extruders_ = num_extruders; + } + retraction_lengths_ = new double[num_extruders]; + z_lift_heights_ = new double[num_extruders]; +} + +void gcode_position::delete_retraction_lengths_() +{ + if (retraction_lengths_ != NULL) + { + delete[] retraction_lengths_; + retraction_lengths_ = NULL; + } +} + +void gcode_position::delete_z_lift_heights_() +{ + if (z_lift_heights_ != NULL) + { + delete[] z_lift_heights_; + z_lift_heights_ = NULL; + } +} + +int gcode_position::get_num_positions() +{ + return num_pos_; +} + +void gcode_position::add_position(position& pos) +{ + cur_pos_ = (cur_pos_+1) % position_buffer_size_; + positions_[cur_pos_] = pos; + if (num_pos_ < position_buffer_size_) + num_pos_++; +} + +void gcode_position::add_position(parsed_command& cmd) +{ + const int prev_pos = cur_pos_; + cur_pos_ = (cur_pos_+1) % position_buffer_size_; + positions_[cur_pos_] = positions_[prev_pos]; + positions_[cur_pos_].reset_state(); + positions_[cur_pos_].command = cmd; + positions_[cur_pos_].is_empty = false; + if (num_pos_ < position_buffer_size_) + num_pos_++; +} + +position gcode_position::get_position(int index) +{ + return positions_[(cur_pos_ - index + position_buffer_size_) % position_buffer_size_]; +} + +position gcode_position::get_current_position() +{ + return get_position(0); +} + +position gcode_position::get_previous_position() +{ + return get_position(1); +} + +position * gcode_position::get_position_ptr(int index) +{ + return &positions_[(cur_pos_ - index + position_buffer_size_) % position_buffer_size_]; +} + +position * gcode_position::get_current_position_ptr() +{ + return get_position_ptr(0); +} + +position * gcode_position::get_previous_position_ptr() +{ + + return get_position_ptr(1); +} + +void gcode_position::update(parsed_command& command, const long file_line_number, const long gcode_number, const long file_position) +{ + + /*if (command.is_empty) + { + // process any comment sections + comment_processor_.update(command.comment); + return; + }*/ + + add_position(command); + position * p_current_pos = get_current_position_ptr(); + position * p_previous_pos = get_previous_position_ptr(); + p_current_pos->file_line_number = file_line_number; + p_current_pos->gcode_number = gcode_number; + p_current_pos->file_position = file_position; + comment_processor_.update(*p_current_pos); + + if (!command.is_known_command || command.is_empty) + return; + + // Does our function exist in our functions map? + gcode_functions_iterator_ = gcode_functions_.find(command.command); + + if (gcode_functions_iterator_ != gcode_functions_.end()) + { + p_current_pos->gcode_ignored = false; + // Execute the function to process this gcode + const pos_function_type func = gcode_functions_iterator_->second; + (this->*func)(p_current_pos, command); + // calculate z and e relative distances + p_current_pos->get_current_extruder().e_relative = (p_current_pos->get_current_extruder().e - p_previous_pos->get_extruder(p_current_pos->current_tool).e); + p_current_pos->z_relative = (p_current_pos->z - p_previous_pos->z); + // Have the XYZ positions changed after processing a command ? + + p_current_pos->has_xy_position_changed = ( + !utilities::is_equal(p_current_pos->x, p_previous_pos->x) || + !utilities::is_equal(p_current_pos->y, p_previous_pos->y) + ); + p_current_pos->has_position_changed = ( + p_current_pos->has_xy_position_changed || + !utilities::is_equal(p_current_pos->z, p_previous_pos->z) || + !utilities::is_zero(p_current_pos->get_current_extruder().e_relative) || + p_current_pos->x_null != p_previous_pos->x_null || + p_current_pos->y_null != p_previous_pos->y_null || + p_current_pos->z_null != p_previous_pos->z_null); + + // see if our position is homed + if (!p_current_pos->has_definite_position) + { + p_current_pos->has_definite_position = ( + //p_current_pos->x_homed_ && + //p_current_pos->y_homed_ && + //p_current_pos->z_homed_ && + p_current_pos->is_metric && + !p_current_pos->is_metric_null && + !p_current_pos->x_null && + !p_current_pos->y_null && + !p_current_pos->z_null && + !p_current_pos->is_relative_null && + !p_current_pos->is_extruder_relative_null); + } + } + + if (p_current_pos->has_position_changed) + { + p_current_pos->get_current_extruder().extrusion_length_total += p_current_pos->get_current_extruder().e_relative; + + if ( + utilities::greater_than(p_current_pos->get_current_extruder().e_relative, 0) && + p_previous_pos->current_tool == p_current_pos->current_tool && + // notice we can use the previous position's current extruder since we've made sure they are using the same tool + p_previous_pos->get_current_extruder().is_extruding && + !p_previous_pos->get_current_extruder().is_extruding_start) + { + // A little shortcut if we know we were extruding (not starting extruding) in the previous command + // This lets us skip a lot of the calculations for the extruder, including the state calculation + p_current_pos->get_current_extruder().extrusion_length = p_current_pos->get_current_extruder().e_relative; + } + else + { + + // Update retraction_length and extrusion_length + p_current_pos->get_current_extruder().retraction_length = p_current_pos->get_current_extruder().retraction_length - p_current_pos->get_current_extruder().e_relative; + if (utilities::less_than_or_equal(p_current_pos->get_current_extruder().retraction_length, 0)) + { + // we can use the negative retraction length to calculate our extrusion length! + p_current_pos->get_current_extruder().extrusion_length = -1.0 * p_current_pos->get_current_extruder().retraction_length; + // set the retraction length to 0 since we are extruding + p_current_pos->get_current_extruder().retraction_length = 0; + } + else + p_current_pos->get_current_extruder().extrusion_length = 0; + + // calculate deretraction length + if (utilities::greater_than(p_previous_pos->get_extruder(p_current_pos->current_tool).retraction_length, p_current_pos->get_current_extruder().retraction_length)) + { + p_current_pos->get_current_extruder().deretraction_length = p_previous_pos->get_extruder(p_current_pos->current_tool).retraction_length - p_current_pos->get_current_extruder().retraction_length; + } + else + p_current_pos->get_current_extruder().deretraction_length = 0; + + // *************Calculate extruder state************* + // rounding should all be done by now + if(p_current_pos->current_tool == p_previous_pos->current_tool) + { + // On a toolchange some flags are not possible, so don't change them. + // these flags include like is_extruding, is_extruding_start, is_retracting_start, is_retracting, is_deretracting_start and is_deretracting + // Note that it's ok to use the previous pos current extruder since we've made sure the current tool is identical + p_current_pos->get_current_extruder().is_extruding_start = utilities::greater_than(p_current_pos->get_current_extruder().extrusion_length, 0) && !p_previous_pos->get_current_extruder().is_extruding; + p_current_pos->get_current_extruder().is_extruding = utilities::greater_than(p_current_pos->get_current_extruder().extrusion_length, 0); + p_current_pos->get_current_extruder().is_retracting_start = !p_previous_pos->get_current_extruder().is_retracting && utilities::greater_than(p_current_pos->get_current_extruder().retraction_length, 0); + p_current_pos->get_current_extruder().is_retracting = utilities::greater_than(p_current_pos->get_current_extruder().retraction_length, p_previous_pos->get_current_extruder().retraction_length); + p_current_pos->get_current_extruder().is_deretracting = utilities::greater_than(p_current_pos->get_current_extruder().deretraction_length, p_previous_pos->get_current_extruder().deretraction_length); + p_current_pos->get_current_extruder().is_deretracting_start = utilities::greater_than(p_current_pos->get_current_extruder().deretraction_length, 0) && !p_previous_pos->get_current_extruder().is_deretracting; + } + else + { + p_current_pos->get_current_extruder().is_extruding_start = false; + p_current_pos->get_current_extruder().is_extruding = false; + p_current_pos->get_current_extruder().is_retracting_start = false; + p_current_pos->get_current_extruder().is_retracting = false; + p_current_pos->get_current_extruder().is_deretracting = false; + p_current_pos->get_current_extruder().is_deretracting_start = false; + } + p_current_pos->get_current_extruder().is_primed = utilities::is_zero(p_current_pos->get_current_extruder().extrusion_length) && utilities::is_zero(p_current_pos->get_current_extruder().retraction_length); + p_current_pos->get_current_extruder().is_partially_retracted = utilities::greater_than(p_current_pos->get_current_extruder().retraction_length, 0) && utilities::less_than(p_current_pos->get_current_extruder().retraction_length, retraction_lengths_[p_current_pos->current_tool]); + p_current_pos->get_current_extruder().is_retracted = utilities::greater_than_or_equal(p_current_pos->get_current_extruder().retraction_length, retraction_lengths_[p_current_pos->current_tool]); + p_current_pos->get_current_extruder().is_deretracted = utilities::greater_than(p_previous_pos->get_extruder(p_current_pos->current_tool).retraction_length, 0) && utilities::is_zero(p_current_pos->get_current_extruder().retraction_length); + // *************End Calculate extruder state************* + } + + // Calcluate position restructions + // TODO: INCLUDE POSITION RESTRICTION CALCULATIONS! + // Set is_in_bounds_ to false if we're not in bounds, it will be true at this point + bool is_in_bounds = true; + if (is_bound_) + { + if (!is_circular_bed_) + { + is_in_bounds = !( + utilities::less_than(p_current_pos->x, snapshot_x_min_) || + utilities::greater_than(p_current_pos->x, snapshot_x_max_) || + utilities::less_than(p_current_pos->y, snapshot_y_min_) || + utilities::greater_than(p_current_pos->y, snapshot_y_max_) || + utilities::less_than(p_current_pos->z, snapshot_z_min_) || + utilities::greater_than(p_current_pos->z, snapshot_z_max_) + ); + + } + else + { + double r; + r = snapshot_x_max_; // good stand in for radius + const double dist = sqrt(p_current_pos->x*p_current_pos->x + p_current_pos->y*p_current_pos->y); + is_in_bounds = utilities::less_than_or_equal(dist, r); + + } + p_current_pos->is_in_bounds = is_in_bounds; + } + + // calculate last_extrusion_height and height + // If we are extruding on a higher level, or if retract is enabled and the nozzle is primed + // adjust the last extrusion height + if (utilities::greater_than(p_current_pos->z, p_current_pos->last_extrusion_height)) + { + if (!p_current_pos->z_null) + { + // detect layer changes/ printer priming/last extrusion height and height + // Normally we would only want to use is_extruding, but we can also use is_deretracted if the layer is greater than 0 + if (p_current_pos->get_current_extruder().is_extruding || (p_current_pos->layer >0 && p_current_pos->get_current_extruder().is_deretracted)) + { + // Is Primed + if (!p_current_pos->is_printer_primed) + { + // We haven't primed yet, check to see if we have priming height restrictions + if (utilities::greater_than(priming_height_, 0)) + { + // if a priming height is configured, see if we've extruded below the height + if (utilities::less_than(p_current_pos->z, priming_height_)) + p_current_pos->is_printer_primed = true; + } + else + // if we have no priming height set, just set is_printer_primed = true. + p_current_pos->is_printer_primed = true; + } + + if (p_current_pos->is_printer_primed && is_in_bounds) + { + // Update the last extrusion height + p_current_pos->last_extrusion_height = p_current_pos->z; + p_current_pos->last_extrusion_height_null = false; + + // Calculate current height + if (utilities::greater_than_or_equal(p_current_pos->z, p_previous_pos->height + minimum_layer_height_)) + { + p_current_pos->height = p_current_pos->z; + p_current_pos->is_layer_change = true; + p_current_pos->layer++; + if (height_increment_ != 0) + { + const double increment_double = p_current_pos->height / height_increment_; + const int increment = utilities::round_up_to_int(increment_double); + if (increment > p_current_pos->height_increment && increment > 1) + { + p_current_pos->height_increment = increment; + p_current_pos->is_height_increment_change = true; + p_current_pos->height_increment_change_count++; + } + } + } + } + } + + // calculate is_zhop + if (p_current_pos->get_current_extruder().is_extruding || p_current_pos->z_null || p_current_pos->last_extrusion_height_null) + p_current_pos->is_zhop = false; + else + p_current_pos->is_zhop = utilities::greater_than_or_equal(p_current_pos->z - p_current_pos->last_extrusion_height, z_lift_heights_[p_current_pos->current_tool]); + } + + } + + + + } +} + +void gcode_position::undo_update() +{ + if (num_pos_ != 0) + { + cur_pos_ = (cur_pos_ - 1 + position_buffer_size_) % position_buffer_size_; + num_pos_--; + } +} + +position* gcode_position::undo_update(int num_updates) +{ + if (num_updates < 1) + return NULL; + + // Create an array of position pointers that will contain the removed positions + position* p_undo_positions = new position[num_updates]; + + // add the positions we will undo to the array + for (int index = 0; index < num_updates; index++) + { + p_undo_positions[index] = get_position(index); + } + + if (num_pos_ < num_updates) + { + num_pos_ = 0; + cur_pos_ = 0; + } + else + { + cur_pos_ = (cur_pos_ - num_updates + position_buffer_size_) % position_buffer_size_; + num_pos_ -= num_updates; + } + return p_undo_positions; + +} + +// Private Members +std::map<std::string, gcode_position::pos_function_type> gcode_position::get_gcode_functions() +{ + std::map<std::string, pos_function_type> newMap; + newMap.insert(std::make_pair("G0", &gcode_position::process_g0_g1)); + newMap.insert(std::make_pair("G1", &gcode_position::process_g0_g1)); + newMap.insert(std::make_pair("G2", &gcode_position::process_g2)); + newMap.insert(std::make_pair("G3", &gcode_position::process_g3)); + newMap.insert(std::make_pair("G10", &gcode_position::process_g10)); + newMap.insert(std::make_pair("G11", &gcode_position::process_g11)); + newMap.insert(std::make_pair("G20", &gcode_position::process_g20)); + newMap.insert(std::make_pair("G21", &gcode_position::process_g21)); + newMap.insert(std::make_pair("G28", &gcode_position::process_g28)); + newMap.insert(std::make_pair("G90", &gcode_position::process_g90)); + newMap.insert(std::make_pair("G91", &gcode_position::process_g91)); + newMap.insert(std::make_pair("G92", &gcode_position::process_g92)); + newMap.insert(std::make_pair("M82", &gcode_position::process_m82)); + newMap.insert(std::make_pair("M83", &gcode_position::process_m83)); + newMap.insert(std::make_pair("M207", &gcode_position::process_m207)); + newMap.insert(std::make_pair("M208", &gcode_position::process_m208)); + newMap.insert(std::make_pair("M218", &gcode_position::process_m218)); + newMap.insert(std::make_pair("M563", &gcode_position::process_m563)); + newMap.insert(std::make_pair("T", &gcode_position::process_t)); + return newMap; +} + +void gcode_position::update_position( + position* pos, + const double x, + const bool update_x, + const double y, + const bool update_y, + const double z, + const bool update_z, + const double e, + const bool update_e, + const double f, + const bool update_f, + const bool force, + const bool is_g1_g0) const +{ + if (is_g1_g0) + { + if (!update_e) + { + if (update_z) + { + pos->is_xyz_travel = (update_x || update_y); + } + else + { + pos->is_xy_travel = (update_x || update_y); + } + } + + } + if (update_f) + { + pos->f = f; + pos->f_null = false; + } + + if (force) + { + if (update_x) + { + pos->x = x + pos->x_offset - pos->x_firmware_offset; + pos->x_null = false; + } + if (update_y) + { + pos->y = y + pos->y_offset - pos->y_firmware_offset; + pos->y_null = false; + } + if (update_z) + { + pos->z = z + pos->z_offset - pos->z_firmware_offset; + pos->z_null = false; + } + // note that e cannot be null and starts at 0 + if (update_e) + pos->get_current_extruder().e = e + pos->get_current_extruder().e_offset; + return; + } + + if (!pos->is_relative_null) + { + if (pos->is_relative) { + if (update_x) + { + if (!pos->x_null) + pos->x = x + pos->x; + } + if (update_y) + { + if (!pos->y_null) + pos->y = y + pos->y; + } + if (update_z) + { + if (!pos->z_null) + pos->z = z + pos->z; + } + } + else + { + + if (update_x) + { + pos->x_firmware_offset = pos->get_current_extruder().x_firmware_offset; + pos->x = x + pos->x_offset - pos->x_firmware_offset; + pos->x_null = false; + } + if (update_y) + { + pos->y_firmware_offset = pos->get_current_extruder().y_firmware_offset; + pos->y = y + pos->y_offset - pos->y_firmware_offset; + pos->y_null = false; + } + if (update_z) + { + pos->z_firmware_offset = pos->get_current_extruder().z_firmware_offset; + pos->z = z + pos->z_offset - pos->z_firmware_offset; + pos->z_null = false; + } + } + } + + if (update_e) + { + if (!pos->is_extruder_relative_null) + { + if (pos->is_extruder_relative) + { + pos->get_current_extruder().e = e + pos->get_current_extruder().e; + } + else + { + pos->get_current_extruder().e = e + pos->get_current_extruder().e_offset; + } + } + } + +} + +void gcode_position::process_g0_g1(position* pos, parsed_command& cmd) +{ + bool update_x = false; + bool update_y = false; + bool update_z = false; + bool update_e = false; + bool update_f = false; + double x = 0; + double y = 0; + double z = 0; + double e = 0; + double f = 0; + for (unsigned int index = 0; index < cmd.parameters.size(); index++) + { + const parsed_command_parameter p_cur_param = cmd.parameters[index]; + if (p_cur_param.name == "X") + { + update_x = true; + x = p_cur_param.double_value; + } + else if (p_cur_param.name == "Y") + { + update_y = true; + y = p_cur_param.double_value; + } + else if (p_cur_param.name == "E") + { + update_e = true; + e = p_cur_param.double_value; + } + else if (p_cur_param.name == "Z") + { + update_z = true; + z = p_cur_param.double_value; + } + else if (p_cur_param.name == "F") + { + update_f = true; + f = p_cur_param.double_value; + } + } + update_position(pos, x, update_x, y, update_y, z, update_z, e, update_e, f, update_f, false, true); +} + +void gcode_position::process_g2(position* pos, parsed_command& cmd) +{ + bool update_x = false; + bool update_y = false; + bool update_e = false; + bool update_f = false; + double x = 0; + double y = 0; + double e = 0; + double f = 0; + for (unsigned int index = 0; index < cmd.parameters.size(); index++) + { + const parsed_command_parameter p_cur_param = cmd.parameters[index]; + if (p_cur_param.name == "X") + { + update_x = true; + x = p_cur_param.double_value; + } + else if (p_cur_param.name == "Y") + { + update_y = true; + y = p_cur_param.double_value; + } + else if (p_cur_param.name == "E") + { + update_e = true; + e = p_cur_param.double_value; + } + else if (p_cur_param.name == "F") + { + update_f = true; + f = p_cur_param.double_value; + } + } + update_position(pos, x, update_x, y, update_y, 0, false, e, update_e, f, update_f, false, true); +} + +void gcode_position::process_g3(position* pos, parsed_command& cmd) +{ + return process_g2(pos, cmd); +} + +void gcode_position::process_g10(position* pos, parsed_command& cmd) +{ + // Take 0 based extruder parameter in account + int p = 0; + bool has_p = false; + double x = 0; + bool has_x = false; + double y = 0; + bool has_y = false; + double z = 0; + bool has_z = false; + //double s = 0; + // Handle extruder offset commands + for (unsigned int index = 0; index < cmd.parameters.size(); index++) + { + parsed_command_parameter p_cur_param = cmd.parameters[index]; + /*if (p_cur_param.name == "S") + { + if (p_cur_param.value_type == 'F') + s = p_cur_param.double_value; + } + else */ + if (p_cur_param.name == "P") + { + has_p = true; + if (p_cur_param.value_type == 'L') + { + p = static_cast<int>(p_cur_param.unsigned_long_value); + } + else if (p_cur_param.value_type == 'F') + { + double val = p_cur_param.double_value; + val = val + 0.5 - (val < 0); + p = static_cast<int>(val); + } + else + has_p = false; + } + else if (p_cur_param.name == "X") + { + has_x = true; + if (p_cur_param.value_type == 'F') + x = p_cur_param.double_value; + else + has_x = false; + } + else if (p_cur_param.name == "Y") + { + has_y = true; + if (p_cur_param.value_type == 'F') + y = p_cur_param.double_value; + else + has_y = false; + } + else if (p_cur_param.name == "Z") + { + has_z = true; + if (p_cur_param.value_type == 'F') + z = p_cur_param.double_value; + else + has_z = false; + } + } + // apply offsets + if (has_p) + { + // Take 0 based extruder parameter in account before setting offsets + if (!zero_based_extruder_) + { + p--; + } + if (p < 0) + { + p = 0; + } + else if (p > num_extruders_ - 1) + { + p = num_extruders_ - 1; + } + if (has_x) + pos->get_extruder(p).x_firmware_offset = x; + if (has_y) + pos->get_extruder(p).y_firmware_offset = y; + if (has_z) + pos->get_extruder(p).z_firmware_offset = z; + return; + } + + // Todo: add firmware retract here +} + +void gcode_position::process_g11(position* pos, parsed_command& cmd) +{ + // Todo: Fix G11 +} + +void gcode_position::process_g20(position* pos, parsed_command& cmd) +{ + +} + +void gcode_position::process_g21(position* pos, parsed_command& cmd) +{ + +} + +void gcode_position::process_g28(position* pos, parsed_command& cmd) +{ + bool has_x = false; + bool has_y = false; + bool has_z = false; + bool set_x_home = false; + bool set_y_home = false; + bool set_z_home = false; + + for (unsigned int index = 0; index < cmd.parameters.size(); index++) + { + parsed_command_parameter p_cur_param = cmd.parameters[index]; + if (p_cur_param.name == "X") + has_x = true; + else if (p_cur_param.name == "Y") + has_y = true; + else if (p_cur_param.name == "Z") + has_z = true; + } + if (has_x) + { + pos->x_homed = true; + set_x_home = true; + } + if (has_y) + { + pos->y_homed = true; + set_y_home = true; + } + if (has_z) + { + pos->z_homed = true; + set_z_home = true; + } + if (!has_x && !has_y && !has_z) + { + pos->x_homed = true; + pos->y_homed = true; + pos->z_homed = true; + set_x_home = true; + set_y_home = true; + set_z_home = true; + } + + if (set_x_home && !home_x_none_) + { + pos->x = home_x_; + pos->x_null = false; + } + // todo: set error flag on else + if (set_y_home && !home_y_none_) + { + pos->y = home_y_; + pos->y_null = false; + } + // todo: set error flag on else + if (set_z_home && !home_z_none_) + { + pos->z = home_z_; + pos->z_null = false; + } + // todo: set error flag on else +} + +void gcode_position::process_g90(position* pos, parsed_command& cmd) +{ + // Set xyz to absolute mode + if (pos->is_relative_null) + pos->is_relative_null = false; + + pos->is_relative = false; + + if (g90_influences_extruder_) + { + // If g90/g91 influences the extruder, set the extruder to absolute mode too + if (pos->is_extruder_relative_null) + pos->is_extruder_relative_null = false; + + pos->is_extruder_relative = false; + } + +} + +void gcode_position::process_g91(position* pos, parsed_command& cmd) +{ + // Set XYZ axis to relative mode + if (pos->is_relative_null) + pos->is_relative_null = false; + + pos->is_relative = true; + + if (g90_influences_extruder_) + { + // If g90/g91 influences the extruder, set the extruder to relative mode too + if (pos->is_extruder_relative_null) + pos->is_extruder_relative_null = false; + + pos->is_extruder_relative = true; + } +} + +void gcode_position::process_g92(position* pos, parsed_command& cmd) +{ + // Set position offset + bool update_x = false; + bool update_y = false; + bool update_z = false; + bool update_e = false; + bool o_exists = false; + double x = 0; + double y = 0; + double z = 0; + double e = 0; + for (unsigned int index = 0; index < cmd.parameters.size(); index++) + { + parsed_command_parameter p_cur_param = cmd.parameters[index]; + if (p_cur_param.name == "X") + { + update_x = true; + x = p_cur_param.double_value; + } + else if (p_cur_param.name == "Y") + { + update_y = true; + y = p_cur_param.double_value; + } + else if (p_cur_param.name == "E") + { + update_e = true; + e = p_cur_param.double_value; + } + else if (p_cur_param.name == "Z") + { + update_z = true; + z = p_cur_param.double_value; + } + else if (p_cur_param.name == "O") + { + o_exists = true; + } + } + + if (o_exists) + { + // Our fake O parameter exists, set axis to homed! + // This is a workaround to allow folks to use octolapse without homing (for shame, lol!) + pos->x_homed = true; + pos->y_homed = true; + pos->z_homed = true; + } + + if (!o_exists && !update_x && !update_y && !update_z && !update_e) + { + if (!pos->x_null) + pos->x_offset = pos->x + pos->x_firmware_offset; + if (!pos->y_null) + pos->y_offset = pos->y + pos->y_firmware_offset; + if (!pos->z_null) + pos->z_offset = pos->z + pos->z_firmware_offset; + // Todo: Does this reset E too? Figure that $#$$ out Formerlurker! + pos->get_current_extruder().e_offset = pos->get_current_extruder().e; + } + else + { + if (update_x) + { + if (!pos->x_null && pos->x_homed) + pos->x_offset = pos->x - x + pos->x_firmware_offset; + else + { + pos->x = x; + pos->x_offset = 0; + pos->x_null = false; + } + } + if (update_y) + { + if (!pos->y_null && pos->y_homed) + pos->y_offset = pos->y - y + pos->y_firmware_offset; + else + { + pos->y = y; + pos->y_offset = 0; + pos->y_null = false; + } + } + if (update_z) + { + if (!pos->z_null && pos->z_homed) + pos->z_offset = pos->z - z + pos->z_firmware_offset; + else + { + pos->z = z; + pos->z_offset = 0; + pos->z_null = false; + } + } + if (update_e) + { + pos->get_current_extruder().e_offset = pos->get_current_extruder().e - e; + } + } +} + +void gcode_position::process_m82(position* pos, parsed_command& cmd) +{ + // Set extrder mode to absolute + if (pos->is_extruder_relative_null) + pos->is_extruder_relative_null = false; + + pos->is_extruder_relative = false; +} + +void gcode_position::process_m83(position* pos, parsed_command& cmd) +{ + // Set extrder mode to relative + if (pos->is_extruder_relative_null) + pos->is_extruder_relative_null = false; + + pos->is_extruder_relative = true; +} + +void gcode_position::process_m207(position* pos, parsed_command& cmd) +{ + // Todo: impemente firmware retract +} + +void gcode_position::process_m208(position* pos, parsed_command& cmd) +{ + // Todo: implement firmware retract +} + +void gcode_position::process_m218(position* pos, parsed_command& cmd) +{ + + // Set hotend offsets + int t = 0; + bool has_t = false; + double x = 0; + bool has_x = false; + double y = 0; + bool has_y = false; + double z = 0; + bool has_z = false; + // Handle extruder offset commands + for (unsigned int index = 0; index < cmd.parameters.size(); index++) + { + parsed_command_parameter p_cur_param = cmd.parameters[index]; + + if (p_cur_param.name == "T") + { + has_t = true; + if (p_cur_param.value_type == 'L') + { + t = static_cast<int>(p_cur_param.unsigned_long_value); + } + else if (p_cur_param.value_type == 'F') + { + double val = p_cur_param.double_value; + val = val + 0.5 - (val < 0); + t = static_cast<int>(val); + } + else + has_t = false; + + } + else if (p_cur_param.name == "X") + { + has_x = true; + if (p_cur_param.value_type == 'F') + x = p_cur_param.double_value; + else + has_x = false; + } + else if (p_cur_param.name == "Y") + { + has_y = true; + if (p_cur_param.value_type == 'F') + y = p_cur_param.double_value; + else + has_y = false; + } + else if (p_cur_param.name == "Z") + { + has_z = true; + if (p_cur_param.value_type == 'F') + z = p_cur_param.double_value; + else + has_z = false; + } + } + // apply offsets + if (has_t) + { + // Take 0 based extruder parameter in account before setting offsets + if (!zero_based_extruder_) + { + t--; + } + if (t < 0) + { + t = 0; + } + else if (t > num_extruders_ - 1) + { + t = num_extruders_ - 1; + } + + if (has_x) + pos->get_extruder(t).x_firmware_offset = x; + if (has_y) + pos->get_extruder(t).y_firmware_offset = y; + if (has_z) + pos->get_extruder(t).z_firmware_offset = z; + return; + } +} + +void gcode_position::process_m563(position* pos, parsed_command& cmd) +{ + // Todo: Work on this command, which defines tools and will affect which tool is selected. +} + +void gcode_position::process_t(position* pos, parsed_command& cmd) +{ + for (unsigned int index = 0; index < cmd.parameters.size(); index++) + { + parsed_command_parameter p_cur_param = cmd.parameters[index]; + if (p_cur_param.name == "T" && p_cur_param.value_type == 'U') + { + pos->current_tool = static_cast<int>(p_cur_param.unsigned_long_value); + if (!zero_based_extruder_) + { + pos->current_tool--; + } + if (pos->current_tool < 0) + { + pos->current_tool = 0; + } + else if (pos->current_tool > num_extruders_ - 1) + { + pos->current_tool = num_extruders_ - 1; + } + + break; + } + } +} + +gcode_comment_processor* gcode_position::get_gcode_comment_processor() +{ + return &comment_processor_; +}
\ No newline at end of file |