diff options
author | FormerLurker <hochgebe@gmail.com> | 2020-04-26 01:20:39 +0300 |
---|---|---|
committer | FormerLurker <hochgebe@gmail.com> | 2020-04-26 01:20:39 +0300 |
commit | 4fcf89d4995921b89b579d06052df11b66e4879f (patch) | |
tree | 390bbfcab87591e802f9ac91ac2d531b4ae53946 /ArcWelder/arc_welder.cpp |
Add project files.
Diffstat (limited to 'ArcWelder/arc_welder.cpp')
-rw-r--r-- | ArcWelder/arc_welder.cpp | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp new file mode 100644 index 0000000..47a61f2 --- /dev/null +++ b/ArcWelder/arc_welder.cpp @@ -0,0 +1,745 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Arc Welder: Anti-Stutter Library +// +// Compresses many G0/G1 commands into G2/G3(arc) commands where possible, ensuring the tool paths stay within the specified resolution. +// This reduces file size and the number of gcodes per second. +// +// Uses the 'Gcode Processor Library' for gcode parsing, position processing, logging, and other various functionality. +// +// 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 "arc_welder.h" +#include <time.h> +#include <vector> +#include <sstream> +#include "utilities.h" +#include <iostream> +#include <fstream> +#include <iomanip> +#include <sstream> +arc_welder::arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, gcode_position_args args) : current_arc_(gcode_position_args_.position_buffer_size - 5, resolution_mm) +{ + p_logger_ = log; + debug_logging_enabled_ = false; + info_logging_enabled_ = false; + error_logging_enabled_ = false; + verbose_logging_enabled_ = false; + + logger_type_ = 0; + progress_callback_ = NULL; + verbose_output_ = false; + absolute_e_offset_total_ = 0; + source_path_ = source_path; + target_path_ = target_path; + resolution_mm_ = resolution_mm; + gcode_position_args_ = args; + notification_period_seconds = 1; + lines_processed_ = 0; + gcodes_processed_ = 0; + file_size_ = 0; + last_gcode_line_written_ = 0; + points_compressed_ = 0; + arcs_created_ = 0; + waiting_for_line_ = false; + waiting_for_arc_ = false; + absolute_e_offset_ = 0; + gcode_position_args_.set_num_extruders(8); + for (int index = 0; index < 8; index++) + { + gcode_position_args_.retraction_lengths[0] = .0001; + gcode_position_args_.z_lift_heights[0] = 0.001; + gcode_position_args_.x_firmware_offsets[0] = 0.0; + gcode_position_args_.y_firmware_offsets[0] = 0.0; + } + + // We don't care about the printer settings, except for g91 influences extruder. + p_source_position_ = new gcode_position(gcode_position_args_); + + // Create a list of commands that will need rewritten absolute e values + std::vector<std::string> absolute_e_rewrite_command_names; + absolute_e_rewrite_command_names.push_back("G0"); + absolute_e_rewrite_command_names.push_back("G1"); + absolute_e_rewrite_command_names.push_back("G2"); + absolute_e_rewrite_command_names.push_back("G3"); + //absolute_e_rewrite_command_names.push_back("G92"); + + for (unsigned int index = 0; index < absolute_e_rewrite_command_names.size(); index++) + { + absolute_e_rewrite_commands_.insert(absolute_e_rewrite_command_names[index]); + } +} + +arc_welder::arc_welder(std::string source_path, std::string target_path, logger* log, double resolution_mm, bool g90_g91_influences_extruder, int buffer_size) + : arc_welder(source_path, target_path, log, resolution_mm, arc_welder::get_args_(g90_g91_influences_extruder, buffer_size)) +{ + +} + +arc_welder::arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, bool g90_g91_influences_extruder, int buffer_size, progress_callback callback) + : arc_welder(source_path, target_path, log, resolution_mm, arc_welder::get_args_(g90_g91_influences_extruder, buffer_size)) +{ + progress_callback_ = callback; +} + +gcode_position_args arc_welder::get_args_(bool g90_g91_influences_extruder, int buffer_size) +{ + gcode_position_args args; + // Configure gcode_position_args + args.g90_influences_extruder = g90_g91_influences_extruder; + args.position_buffer_size = buffer_size; + args.autodetect_position = true; + args.home_x = 0; + args.home_x_none = true; + args.home_y = 0; + args.home_y_none = true; + args.home_z = 0; + args.home_z_none = true; + args.shared_extruder = true; + args.zero_based_extruder = true; + + + args.default_extruder = 0; + args.xyz_axis_default_mode = "absolute"; + args.e_axis_default_mode = "absolute"; + args.units_default = "millimeters"; + args.location_detection_commands = std::vector<std::string>(); + args.is_bound_ = false; + args.is_circular_bed = false; + args.x_min = -9999; + args.x_max = 9999; + args.y_min = -9999; + args.y_max = 9999; + args.z_min = -9999; + args.z_max = 9999; + return args; +} + +arc_welder::~arc_welder() +{ + delete p_source_position_; +} + +void arc_welder::set_logger_type(int logger_type) +{ + logger_type_ = logger_type; +} + +void arc_welder::reset() +{ + lines_processed_ = 0; + gcodes_processed_ = 0; + last_gcode_line_written_ = 0; + file_size_ = 0; + points_compressed_ = 0; + arcs_created_ = 0; + waiting_for_line_ = false; + waiting_for_arc_ = false; + absolute_e_offset_ = 0; +} + +long arc_welder::get_file_size(const std::string& file_path) +{ + // Todo: Fix this function. This is a pretty weak implementation :( + std::ifstream file(file_path.c_str(), std::ios::in | std::ios::binary); + const long l = (long)file.tellg(); + file.seekg(0, std::ios::end); + const long m = (long)file.tellg(); + file.close(); + return (m - l); +} + +double arc_welder::get_next_update_time() const +{ + return clock() + (notification_period_seconds * CLOCKS_PER_SEC); +} + +double arc_welder::get_time_elapsed(double start_clock, double end_clock) +{ + return static_cast<double>(end_clock - start_clock) / CLOCKS_PER_SEC; +} + +void arc_welder::process() +{ + verbose_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, VERBOSE); + debug_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, DEBUG); + info_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, INFO); + error_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, ERROR); + // reset tracking variables + reset(); + // local variable to hold the progress update return. If it's false, we will exit. + bool continue_processing = true; + + // Create a stringstream we can use for messaging. + std::stringstream stream; + + int read_lines_before_clock_check = 5000; + double next_update_time = get_next_update_time(); + const clock_t start_clock = clock(); + file_size_ = get_file_size(source_path_); + // Create the source file read stream and target write stream + std::ifstream gcodeFile; + gcodeFile.open(source_path_.c_str()); + output_file_.open(target_path_.c_str()); + std::string line; + int lines_with_no_commands = 0; + gcodeFile.sync_with_stdio(false); + output_file_.sync_with_stdio(false); + if (gcodeFile.is_open()) + { + if (output_file_.is_open()) + { + if (info_logging_enabled_) + { + stream.clear(); + stream.str(""); + stream << "Opened file for reading. File Size: " << file_size_; + p_logger_->log(logger_type_, DEBUG, stream.str()); + } + parsed_command cmd; + // Communicate every second + while (std::getline(gcodeFile, line) && continue_processing) + { + lines_processed_++; + + cmd.clear(); + parser_.try_parse_gcode(line.c_str(), cmd); + bool has_gcode = false; + if (cmd.gcode.length() > 0) + { + has_gcode = true; + gcodes_processed_++; + } + else + { + lines_with_no_commands++; + } + + // Always process the command through the printer, even if no command is found + // This is important so that comments can be analyzed + //std::cout << "stabilization::process_file - updating position..."; + process_gcode(cmd, false); + + // Only continue to process if we've found a command. + if (has_gcode) + { + if ((lines_processed_ % read_lines_before_clock_check) == 0 && next_update_time < clock()) + { + long file_position = static_cast<long>(gcodeFile.tellg()); + // ToDo: tellg does not do what I think it does, but why? + long bytesRemaining = file_size_ - file_position; + double percentProgress = static_cast<double>(file_position) / static_cast<double>(file_size_) * 100.0; + double secondsElapsed = get_time_elapsed(start_clock, clock()); + double bytesPerSecond = static_cast<double>(file_position) / secondsElapsed; + double secondsToComplete = bytesRemaining / bytesPerSecond; + continue_processing = on_progress_(percentProgress, secondsElapsed, secondsToComplete, gcodes_processed_, lines_processed_, points_compressed_, arcs_created_); + next_update_time = get_next_update_time(); + } + } + } + + if (current_arc_.is_shape() && waiting_for_arc_) + { + process_gcode(cmd, true); + } + write_unwritten_gcodes_to_file(); + + output_file_.close(); + } + else + { + p_logger_->log_exception(logger_type_, "Unable to open the output file for writing."); + } + gcodeFile.close(); + } + else + { + p_logger_->log_exception(logger_type_, "Unable to open the gcode file for processing."); + } + + const clock_t end_clock = clock(); + const double total_seconds = static_cast<double>(end_clock - start_clock) / CLOCKS_PER_SEC; + on_progress_(100, total_seconds, 0, gcodes_processed_, lines_processed_, points_compressed_, arcs_created_); +} + +bool arc_welder::on_progress_(double percentComplete, double seconds_elapsed, double estimatedSecondsRemaining, int gcodesProcessed, int linesProcessed, int points_compressed, int arcs_created) +{ + if (progress_callback_ != NULL) + { + return progress_callback_(percentComplete, seconds_elapsed, estimatedSecondsRemaining, gcodesProcessed, linesProcessed, points_compressed, arcs_created); + } + std::stringstream stream; + if (debug_logging_enabled_) + { + stream << percentComplete << "% complete in " << seconds_elapsed << " seconds with " << estimatedSecondsRemaining << " seconds remaining. Gcodes Processed:" << gcodesProcessed << ", Current Line:" << linesProcessed << ", Points Compressed:" << points_compressed << ", ArcsCreated:" << arcs_created; + p_logger_->log(logger_type_, DEBUG, stream.str()); + } + + return true; +} + +int arc_welder::process_gcode(parsed_command cmd, bool is_end) +{ + // Update the position for the source gcode file + p_source_position_->update(cmd, lines_processed_, gcodes_processed_, -1); + + position* p_cur_pos = p_source_position_->get_current_position_ptr(); + position* p_pre_pos = p_source_position_->get_previous_position_ptr(); + //std::cout << lines_processed_ << " - " << cmd.gcode << ", CurrentEAbsolute: " << cur_extruder.e <<", ExtrusionLength: " << cur_extruder.extrusion_length << ", Retraction Length: " << cur_extruder.retraction_length << ", IsExtruding: " << cur_extruder.is_extruding << ", IsRetracting: " << cur_extruder.is_retracting << ".\n"; + + int lines_written = 0; + // see if this point is an extrusion + + bool arc_added = false; + bool clear_shapes = false; + + extruder extruder_current = p_cur_pos->get_current_extruder(); + point p(p_cur_pos->x, p_cur_pos->y, p_cur_pos->z, extruder_current.e_relative); + + // We need to make sure the printer is using absolute xyz, is extruding, and the extruder axis mode is the same as that of the previous position + // TODO: Handle relative XYZ axis. This is possible, but maybe not so important. + if ( + !is_end && cmd.is_known_command && !cmd.is_empty && ( + (cmd.command == "G0" || cmd.command == "G1") && + utilities::is_equal(p_cur_pos->z, p_pre_pos->z) && + !p_cur_pos->is_relative && + ( + !waiting_for_arc_ || + (p_pre_pos->get_current_extruder().is_extruding && extruder_current.is_extruding) || + (p_pre_pos->get_current_extruder().is_retracting && extruder_current.is_retracting) + ) && + p_cur_pos->is_extruder_relative == p_pre_pos->is_extruder_relative && + (!waiting_for_arc_ || p_pre_pos->f == p_cur_pos->f) && + (!waiting_for_arc_ || p_pre_pos->feature_type_tag == p_cur_pos->feature_type_tag) + ) + ) { + + if (!waiting_for_arc_) + { + if (debug_logging_enabled_) + { + p_logger_->log(logger_type_, DEBUG, "Starting new arc from Gcode:" + cmd.gcode); + } + write_unwritten_gcodes_to_file(); + // add the previous point as the starting point for the current arc + point previous_p(p_pre_pos->x, p_pre_pos->y, p_pre_pos->z, p_pre_pos->get_current_extruder().e_relative); + // Don't add any extrusion, or you will over extrude! + //std::cout << "Trying to add first point (" << p.x << "," << p.y << "," << p.z << ")..."; + current_arc_.try_add_point(previous_p, 0); + } + + double e_relative = p_cur_pos->get_current_extruder().e_relative; + int num_points = current_arc_.get_num_segments(); + arc_added = current_arc_.try_add_point(p, e_relative); + if (arc_added) + { + if (!waiting_for_arc_) + { + waiting_for_arc_ = true; + } + else + { + if (debug_logging_enabled_) + { + if (num_points+1 == current_arc_.get_num_segments()) + { + p_logger_->log(logger_type_, DEBUG, "Adding point to arc from Gcode:" + cmd.gcode); + } + { + p_logger_->log(logger_type_, DEBUG, "Removed start point from arc and added a new point from Gcode:" + cmd.gcode); + } + } + } + } + } + else if (debug_logging_enabled_ ){ + if (is_end) + { + p_logger_->log(logger_type_, DEBUG, "Procesing final shape, if one exists."); + } + else if (!cmd.is_empty) + { + if (!cmd.is_known_command) + { + p_logger_->log(logger_type_, DEBUG, "Command '" + cmd.command + "' is Unknown. Gcode:" + cmd.gcode); + } + else if (cmd.command != "G0" && cmd.command != "G1") + { + p_logger_->log(logger_type_, DEBUG, "Command '"+ cmd.command + "' is not G0/G1, skipping. Gcode:" + cmd.gcode); + } + else if (!utilities::is_equal(p_cur_pos->z, p_pre_pos->z)) + { + p_logger_->log(logger_type_, DEBUG, "Z axis position changed, cannot convert:" + cmd.gcode); + } + else if (p_cur_pos->is_relative) + { + p_logger_->log(logger_type_, DEBUG, "XYZ Axis is in relative mode, cannot convert:" + cmd.gcode); + } + else if ( + waiting_for_arc_ && !( + (p_pre_pos->get_current_extruder().is_extruding && extruder_current.is_extruding) || + (p_pre_pos->get_current_extruder().is_retracting && extruder_current.is_retracting) + ) + ) + { + std::string message = "Extruding or retracting state changed, cannot add point to current arc: " + cmd.gcode; + if (verbose_logging_enabled_) + { + extruder previous_extruder = p_pre_pos->get_current_extruder(); + message.append( + " - Verbose Info\n\tCurrent Position Info - Absolute E:" + utilities::to_string(extruder_current.e) + + ", Offset E:" + utilities::to_string(extruder_current.get_offset_e()) + + ", Mode:" + (p_cur_pos->is_extruder_relative_null ? "NULL" : p_cur_pos->is_extruder_relative ? "relative" : "absolute") + + ", Retraction: " + utilities::to_string(extruder_current.retraction_length) + + ", Extrusion: " + utilities::to_string(extruder_current.extrusion_length) + + ", Retracting: " + (extruder_current.is_retracting ? "True" : "False") + + ", Extruding: " + (extruder_current.is_extruding ? "True" : "False") + ); + message.append( + "\n\tPrevious Position Info - Absolute E:" + utilities::to_string(previous_extruder.e) + + ", Offset E:" + utilities::to_string(previous_extruder.get_offset_e()) + + ", Mode:" + (p_pre_pos->is_extruder_relative_null ? "NULL" : p_pre_pos->is_extruder_relative ? "relative" : "absolute") + + ", Retraction: " + utilities::to_string(previous_extruder.retraction_length) + + ", Extrusion: " + utilities::to_string(previous_extruder.extrusion_length) + + ", Retracting: " + (previous_extruder.is_retracting ? "True" : "False") + + ", Extruding: " + (previous_extruder.is_extruding ? "True" : "False") + ); + p_logger_->log(logger_type_, VERBOSE, message); + } + else + { + p_logger_->log(logger_type_, DEBUG, message); + } + + } + else if (p_cur_pos->is_extruder_relative != p_pre_pos->is_extruder_relative) + { + p_logger_->log(logger_type_, DEBUG, "Extruder axis mode changed, cannot add point to current arc: " + cmd.gcode); + } + else if (waiting_for_arc_ && p_pre_pos->f != p_cur_pos->f) + { + p_logger_->log(logger_type_, DEBUG, "Feedrate changed, cannot add point to current arc: " + cmd.gcode); + } + else if (waiting_for_arc_ && p_pre_pos->feature_type_tag != p_cur_pos->feature_type_tag) + { + p_logger_->log(logger_type_, DEBUG, "Feature type changed, cannot add point to current arc: " + cmd.gcode); + } + else + { + // Todo: Add all the relevant values + p_logger_->log(logger_type_, DEBUG, "There was an unknown issue preventing the current point from being added to the arc: " + cmd.gcode); + } + } + } + if (!arc_added) + { + if (current_arc_.get_num_segments() < current_arc_.get_min_segments()) { + if (debug_logging_enabled_ && !cmd.is_empty) + { + if (current_arc_.get_num_segments() != 0) + { + p_logger_->log(logger_type_, DEBUG, "Not enough segments, resetting. Gcode:" + cmd.gcode); + } + + } + waiting_for_arc_ = false; + current_arc_.clear(); + } + else if (waiting_for_arc_) + { + + if (current_arc_.is_shape()) + { + // increment our statistics + points_compressed_ += current_arc_.get_num_segments()-1; + arcs_created_++; + //std::cout << "Arc shape found.\n"; + // Get the comment now, before we remove the previous comments + std::string comment = get_comment_for_arc(); + // remove the same number of unwritten gcodes as there are arc segments, minus 1 for the start point + // Which isn't a movement + // note, skip the first point, it is the starting point + for (int index = 0; index < current_arc_.get_num_segments() - 1; index++) + { + unwritten_commands_.pop_back(); + } + // get the current absolute e coordinate of the previous position (the current position is not included in + // the arc) so we can make any adjustments that are necessary. + double current_f = p_pre_pos->f; + + // IMPORTANT NOTE: p_cur_pos and p_pre_pos will NOT be usable beyond this point. + p_pre_pos = NULL; + p_cur_pos = NULL; + // Undo the previous updates that will be turned into the arc, including the current position + for (int index = 0; index < current_arc_.get_num_segments(); index++) + { + undo_commands_.push_back(p_source_position_->get_current_position_ptr()->command); + p_source_position_->undo_update(); + } + //position * p_undo_positions = p_source_position_->undo_update(current_arc_.get_num_segments()); + + // Set the current feedrate if it is different, else set to 0 to indicate that no feedrate should be included + if(p_source_position_->get_current_position_ptr()->f == current_f) + { + current_f = 0; + } + + // Craete the arc gcode + std::string gcode = get_arc_gcode(current_f, comment); + + if (debug_logging_enabled_) + { + p_logger_->log(logger_type_, DEBUG, "Arc created with " + std::to_string(current_arc_.get_num_segments()) + " segments: " + gcode); + } + + // parse the arc gcode + parsed_command new_command; + bool parsed = parser_.try_parse_gcode(gcode.c_str(), new_command); + if (!parsed) + { + if (error_logging_enabled_) + { + p_logger_->log_exception(logger_type_, "Unable to parse arc command! Fatal Error."); + } + throw std::exception(); + } + // update the position processor and add the command to the unwritten commands list + p_source_position_->update(new_command, lines_processed_, gcodes_processed_, -1); + unwritten_commands_.push_back(unwritten_command(p_source_position_->get_current_position_ptr())); + + // write all unwritten commands (if we don't do this we'll mess up absolute e by adding an offset to the arc) + // including the most recent arc command BEFORE updating the absolute e offset + write_unwritten_gcodes_to_file(); + + // If the e values are not equal, use G91 to adjust the current absolute e position + double difference = 0; + double new_e_rel_relative = p_source_position_->get_current_position().get_current_extruder().e_relative; + double old_e_relative = current_arc_.get_shape_e_relative(); + + // See if any offset needs to be applied for absolute E coordinates + if ( + !utilities::is_equal(new_e_rel_relative, old_e_relative)) + { + // Calculate the difference between the original absolute e and + // change made by G2/G3 + difference = new_e_rel_relative - old_e_relative; + // Adjust the absolute E offset based on the difference + // We need to do this AFTER writing the modified gcode(arc), since the + // difference is based on that. + absolute_e_offset_ += difference; + if (debug_logging_enabled_) + { + p_logger_->log(logger_type_, DEBUG, "Adjusting absolute extrusion by " + utilities::to_string(difference) + "mm. New Offset: " + utilities::to_string(difference)); + } + } + + + // Undo the arc update and re-apply the original commands to the position processor so that subsequent + // gcodes in the file are interpreted properly. Do NOT add the most recent command + // since it will be reprocessed + p_source_position_->undo_update(); + + for (int index = current_arc_.get_num_segments() - 1; index > 0; index--) + { + parsed_command cmd = undo_commands_.pop_back(); + p_source_position_->update(undo_commands_[index], lines_processed_, gcodes_processed_, -1); + } + undo_commands_.clear(); + // Now clear the arc and flag the processor as not waiting for an arc + waiting_for_arc_ = false; + current_arc_.clear(); + + + // Reprocess this line + if (!is_end) + { + return process_gcode(cmd, false); + } + else + { + if (debug_logging_enabled_) + { + p_logger_->log(logger_type_, DEBUG, "Final arc created, exiting."); + } + return 0; + } + + } + else + { + if (debug_logging_enabled_) + { + p_logger_->log(logger_type_, DEBUG, "The current arc is not a valid arc, resetting."); + } + current_arc_.clear(); + waiting_for_arc_ = false; + } + } + else if (debug_logging_enabled_) + { + p_logger_->log(logger_type_, DEBUG, "Could not add point to arc from gcode:" + cmd.gcode); + } + + } + if (clear_shapes) + { + waiting_for_arc_ = false; + current_arc_.clear(); + // The current command is unwritten, add it. + unwritten_commands_.push_back(unwritten_command(p_source_position_->get_current_position_ptr())); + } + else if (waiting_for_arc_ || !arc_added) + { + + unwritten_commands_.push_back(unwritten_command(p_source_position_->get_current_position_ptr())); + + } + if (!waiting_for_arc_) + { + write_unwritten_gcodes_to_file(); + } + if (cmd.command == "G92") + { + // See if there is an E parameter + for (unsigned int parameter_index = 0; parameter_index < cmd.parameters.size(); parameter_index++) + { + parsed_command_parameter param = cmd.parameters[parameter_index]; + if (param.name == "E") + { + absolute_e_offset_ = 0; + if (debug_logging_enabled_) + { + p_logger_->log(logger_type_, DEBUG, "G92 found that set E axis, resetting absolute offset."); + } + } + } + } + + return lines_written; +} + +std::string arc_welder::get_comment_for_arc() +{ + // build a comment string from the commands making up the arc + // We need to start with the first command entered. + int comment_index = unwritten_commands_.count() - (current_arc_.get_num_segments() - 1); + std::string comment; + for (; comment_index < unwritten_commands_.count(); comment_index++) + { + std::string old_comment = unwritten_commands_[comment_index].command.comment; + if (old_comment != comment && old_comment.length() > 0) + { + if (comment.length() > 0) + { + comment += " - "; + } + comment += old_comment; + } + } + return comment; +} + +std::string arc_welder::create_g92_e(double absolute_e) +{ + std::stringstream stream; + stream << std::fixed << std::setprecision(5); + stream << "G92 E" << absolute_e; + return stream.str(); +} + +int arc_welder::write_gcode_to_file(std::string gcode) +{ + output_file_ << utilities::trim(gcode) << "\n"; + //std::cout << utilities::trim(gcode) << "\n"; + return 1; +} + +int arc_welder::write_unwritten_gcodes_to_file() +{ + int size = unwritten_commands_.count(); + std::string gcode_to_write; + + + for (int index = 0; index < size; index++) + { + // The the current unwritten position and remove it from the list + unwritten_command p = unwritten_commands_.pop_front(); + bool has_e_coordinate = false; + std::string additional_comment = ""; + double old_e = p.offset_e; + double new_e = old_e; + if (!p.is_extruder_relative && utilities::greater_than(abs(absolute_e_offset_), 0.0) && + absolute_e_rewrite_commands_.find(p.command.command) != absolute_e_rewrite_commands_.end() + ){ + // handle any absolute extrusion shift + // There is an offset, and we are in absolute E. Rewrite the gcode + parsed_command new_command = p.command; + new_command.parameters.clear(); + has_e_coordinate = false; + for (unsigned int index = 0; index < p.command.parameters.size(); index++) + { + parsed_command_parameter p_cur_param = p.command.parameters[index]; + if (p_cur_param.name == "E") + { + has_e_coordinate = true; + if (p_cur_param.value_type == 'U') + { + p_cur_param.value_type = 'F'; + } + new_e = p.offset_e + absolute_e_offset_; + p_cur_param.double_value = new_e; + + } + new_command.parameters.push_back(p_cur_param); + } + + + if (has_e_coordinate) + { + p.command = new_command; + } + } + + write_gcode_to_file(p.to_string(has_e_coordinate, additional_comment)); + + } + + return size; +} + +std::string arc_welder::get_arc_gcode(double f, const std::string comment) +{ + // Write gcode to file + std::string gcode; + position* p_new_current_pos = p_source_position_->get_current_position_ptr(); + + if (p_new_current_pos->is_extruder_relative) + { + gcode = current_arc_.get_shape_gcode_relative(f); + } + else + { + // Make sure to add the absoulte e offset + gcode = current_arc_.get_shape_gcode_absolute(f, p_new_current_pos->get_current_extruder().get_offset_e()); + } + if (comment.length() > 0) + { + gcode += ";" + comment; + } + return gcode; + +} |