From 9d3361e145c806a2ea0d3c7f1f6fc7252e4d0ef1 Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Mon, 5 Jul 2021 18:57:33 -0500 Subject: Add alpha gcode length restrictions. Enhance output statistics. Create arc_welder_args. Add new progress type args to command line processor. --- ArcWelder/arc_welder.cpp | 165 ++++++++++++++++++++++----------------- ArcWelder/arc_welder.h | 174 ++++++++++++++++++++++++++++++++++++++---- ArcWelder/segmented_arc.cpp | 83 +++++++++++++++----- ArcWelder/segmented_arc.h | 13 ++-- ArcWelder/segmented_shape.cpp | 8 +- ArcWelder/segmented_shape.h | 20 +++-- ArcWelder/unwritten_command.h | 34 +++------ 7 files changed, 352 insertions(+), 145 deletions(-) (limited to 'ArcWelder') diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp index b45f9e9..0531a67 100644 --- a/ArcWelder/arc_welder.cpp +++ b/ArcWelder/arc_welder.cpp @@ -52,6 +52,7 @@ arc_welder::arc_welder( unsigned char default_xyz_precision, unsigned char default_e_precision, double extrusion_rate_variance_percent, + int max_gcode_length, int buffer_size, progress_callback callback) : current_arc_( DEFAULT_MIN_SEGMENTS, @@ -63,13 +64,19 @@ arc_welder::arc_welder( mm_per_arc_segment, allow_3d_arcs, default_xyz_precision, - default_e_precision + default_e_precision, + max_gcode_length ), segment_statistics_( segment_statistic_lengths, segment_statistic_lengths_count, log - ) + ), + travel_statistics_( + segment_statistic_lengths, + segment_statistic_lengths_count, + log + ) { p_logger_ = log; debug_logging_enabled_ = false; @@ -203,24 +210,6 @@ arc_welder_results results; error_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, ERROR); std::stringstream stream; - stream << std::fixed << std::setprecision(2); - stream << "arc_welder::process - Parameters received: source_file_path: '" << - source_path_ << "', target_file_path:'" << target_path_ << "', resolution_mm:" << - resolution_mm_ << "mm (+-" << current_arc_.get_resolution_mm() - << "mm), path_tolerance_percent: " << current_arc_.get_path_tolerance_percent() - << "%, extrusion_rate_variance_percent: " << extrusion_rate_variance_percent_ - << "%, max_radius_mm:" << current_arc_.get_max_radius() - << ", min_arc_segments:" << std::setprecision(0) <get_g90_91_influences_extruder() ? "True" : "False") - << ", allow_3d_arcs: " << (allow_3d_arcs_ ? "True" : "False") - << ", allow_travel_arcs: " << (allow_travel_arcs_ ? "True" : "False") - << ", allow_dynamic_precision: " << (allow_dynamic_precision_ ? "True" : "False") - << ", default_xyz_precision: " << std::setprecision(0) << static_cast(current_arc_.get_xyz_precision()) - << ", default_e_precision: " << std::setprecision(0) << static_cast(current_arc_.get_e_precision()); - p_logger_->log(logger_type_, INFO, stream.str()); - - // reset tracking variables reset(); // local variable to hold the progress update return. If it's false, we will exit. @@ -236,6 +225,28 @@ arc_welder_results results; stream.str(""); stream << "Source file size: " << file_size_; p_logger_->log(logger_type_, DEBUG, stream.str()); + + // Determine if we need to overwrite the source file + bool overwrite_source_file = false; + std::string temp_file_path; + if (source_path_ == target_path_) + { + overwrite_source_file = true; + if (!utilities::get_temp_file_path_for_file(source_path_, temp_file_path)) + { + results.success = false; + results.message = "The source and target path are the same, but a temporary file path could not be created. Are the paths empty?"; + p_logger_->log_exception(logger_type_, results.message); + return results; + } + + stream.clear(); + stream.str(""); + stream << "Source and target path are the same. The source file will be overwritten. Temporary file path: " << temp_file_path; + p_logger_->log(logger_type_, DEBUG, stream.str()); + target_path_ = temp_file_path; + } + // Create the source file read stream and target write stream std::ifstream gcodeFile; p_logger_->log(logger_type_, DEBUG, "Opening the source file for reading."); @@ -340,6 +351,7 @@ arc_welder_results results; } p_logger_->log(logger_type_, DEBUG, "Writing all unwritten gcodes to the target file."); write_unwritten_gcodes_to_file(); + p_logger_->log(logger_type_, DEBUG, "Fetching the final progress struct."); arc_welder_progress final_progress = get_progress_(static_cast(file_size_), static_cast(start_clock)); @@ -347,13 +359,26 @@ arc_welder_results results; { p_logger_->log(logger_type_, DEBUG, "Sending final progress update message."); } - on_progress_(arc_welder_progress(final_progress)); + on_progress_(final_progress); - p_logger_->log(logger_type_, DEBUG, "Processing complete, closing source and target file."); + p_logger_->log(logger_type_, DEBUG, "Closing source and target files."); output_file_.close(); gcodeFile.close(); - const clock_t end_clock = clock(); - + + if (overwrite_source_file) + { + stream.clear(); + stream.str(""); + stream << "Deleting the original source file at '" << source_path_ << "'."; + p_logger_->log(logger_type_, DEBUG, stream.str()); + stream.clear(); + stream.str(""); + std::remove(source_path_.c_str()); + stream << "Renaming temporary file at '" << target_path_ << "' to '" << source_path_ << "'."; + p_logger_->log(0, DEBUG, stream.str()); + std::rename(target_path_.c_str(), source_path_.c_str()); + } + results.success = continue_processing; results.cancelled = !continue_processing; results.progress = final_progress; @@ -397,8 +422,14 @@ arc_welder_progress arc_welder::get_progress_(long source_file_position, double progress.compression_ratio = (static_cast(source_file_position) / static_cast(progress.target_file_size)); progress.compression_percent = (1.0 - (static_cast(progress.target_file_size) / static_cast(source_file_position))) * 100.0f; } + else { + progress.compression_ratio = 0; + progress.compression_percent = 0; + } progress.num_firmware_compensations = current_arc_.get_num_firmware_compensations(); + progress.num_gcode_length_exceptions = current_arc_.get_num_gcode_length_exceptions(); progress.segment_statistics = segment_statistics_; + progress.travel_statistics = travel_statistics_; return progress; } @@ -427,7 +458,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess bool arc_added = false; bool clear_shapes = false; double movement_length_mm = 0; - bool has_e_changed = extruder_current.is_extruding || extruder_current.is_retracting; + bool has_e_changed = extruder_current.e_relative != 0; // Update the source file statistics if (p_cur_pos->has_xy_position_changed) { @@ -441,7 +472,17 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess if (movement_length_mm > 0) { if (!is_reprocess) - segment_statistics_.update(movement_length_mm, true); + { + if (has_e_changed) + { + segment_statistics_.update(movement_length_mm, true); + } + else if (allow_3d_arcs_) + { + travel_statistics_.update(movement_length_mm, true); + } + + } } } @@ -466,8 +507,8 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess // 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. - bool is_g1_g2 = cmd.command == "G0" || cmd.command == "G1"; - if (allow_dynamic_precision_ && is_g1_g2) + bool is_g0_g1 = cmd.command == "G0" || cmd.command == "G1"; + if (allow_dynamic_precision_ && is_g0_g1) { for (std::vector::iterator it = cmd.parameters.begin(); it != cmd.parameters.end(); ++it) { @@ -490,7 +531,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess if ( !is_end && cmd.is_known_command && !cmd.is_empty && ( - is_g1_g2 && z_axis_ok && + is_g0_g1 && z_axis_ok && utilities::is_equal(p_cur_pos->x_offset, p_pre_pos->x_offset) && utilities::is_equal(p_cur_pos->y_offset, p_pre_pos->y_offset) && utilities::is_equal(p_cur_pos->z_offset, p_pre_pos->z_offset) && @@ -516,7 +557,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess // Record the extrusion rate previous_extrusion_rate_ = mm_extruded_per_mm_travel; - printer_point p(p_cur_pos->get_gcode_x(), p_cur_pos->get_gcode_y(), p_cur_pos->get_gcode_z(), extruder_current.e_relative, movement_length_mm); + printer_point p(p_cur_pos->get_gcode_x(), p_cur_pos->get_gcode_y(), p_cur_pos->get_gcode_z(), extruder_current.get_offset_e() ,extruder_current.e_relative, p_cur_pos->f, movement_length_mm, p_pre_pos->is_extruder_relative); if (!waiting_for_arc_) { if (debug_logging_enabled_) @@ -525,7 +566,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess } write_unwritten_gcodes_to_file(); // add the previous point as the starting point for the current arc - printer_point previous_p(p_pre_pos->get_gcode_x(), p_pre_pos->get_gcode_y(), p_pre_pos->get_gcode_z(), previous_extruder.e_relative, 0); + printer_point previous_p(p_pre_pos->get_gcode_x(), p_pre_pos->get_gcode_y(), p_pre_pos->get_gcode_z(), previous_extruder.get_offset_e(),previous_extruder.e_relative, p_pre_pos->f, 0, p_pre_pos->is_extruder_relative); // Don't add any extrusion, or you will over extrude! //std::cout << "Trying to add first point (" << p.x << "," << p.y << "," << p.z << ")..."; @@ -652,8 +693,6 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess // Reset the previous extrusion rate previous_extrusion_rate_ = 0; } - - if (!arc_added && !(cmd.is_empty && cmd.comment.length() == 0)) { @@ -677,7 +716,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess // update our statistics points_compressed_ += current_arc_.get_num_segments()-1; arcs_created_++; // increment the number of generated arcs - write_arc_gcodes(p_pre_pos->is_extruder_relative, p_pre_pos->f); + write_arc_gcodes(p_pre_pos->f); // Now clear the arc and flag the processor as not waiting for an arc waiting_for_arc_ = false; current_arc_.clear(); @@ -721,7 +760,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess // This might not work.... //position* cur_pos = p_source_position_->get_current_position_ptr(); - unwritten_commands_.push_back(unwritten_command(cmd, is_previous_extruder_relative, movement_length_mm)); + unwritten_commands_.push_back(unwritten_command(cmd, is_previous_extruder_relative, !has_e_changed && is_g0_g1, movement_length_mm)); } else if (!waiting_for_arc_) @@ -732,7 +771,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess return lines_written; } -void arc_welder::write_arc_gcodes(bool is_extruder_relative, double current_feedrate) +void arc_welder::write_arc_gcodes(double current_feedrate) { std::string comment = get_comment_for_arc(); @@ -742,7 +781,7 @@ void arc_welder::write_arc_gcodes(bool is_extruder_relative, double current_feed int num_segments = current_arc_.get_num_segments() - 1; for (int index = 0; index < num_segments; index++) { - while (!unwritten_commands_.pop_back().is_g1_g2); + while (!unwritten_commands_.pop_back().is_g0_g1); } // Undo the current command, since it isn't included in the arc @@ -754,16 +793,8 @@ void arc_welder::write_arc_gcodes(bool is_extruder_relative, double current_feed } // Craete the arc gcode - std::string gcode; - if (is_extruder_relative) { - gcode = get_arc_gcode_relative(current_feedrate, comment); - } - - else { - gcode = get_arc_gcode_absolute(p_source_position_->get_current_position_ptr()->get_current_extruder().get_offset_e(), current_feedrate, comment); - } - - + std::string gcode = get_arc_gcode(comment); + if (debug_logging_enabled_) { char buffer[20]; @@ -779,11 +810,16 @@ void arc_welder::write_arc_gcodes(bool is_extruder_relative, double current_feed write_unwritten_gcodes_to_file(); // Update the current extrusion statistics for the current arc gcode - segment_statistics_.update(current_arc_.get_shape_length() , false); + if (current_arc_.get_shape_e_relative() != 0) + { + segment_statistics_.update(current_arc_.get_shape_length(), false); + + } + else if (allow_3d_arcs_){ + travel_statistics_.update(current_arc_.get_shape_length(), false); + } // now write the current arc to the file write_gcode_to_file(gcode); - - } std::string arc_welder::get_comment_for_arc() @@ -830,9 +866,15 @@ int arc_welder::write_unwritten_gcodes_to_file() { // The the current unwritten position and remove it from the list unwritten_command p = unwritten_commands_.pop_front(); - if (p.extrusion_length > 0) + if(p.is_g0_g1 && p.length > 0) { - segment_statistics_.update(p.extrusion_length, false); + if (!p.is_travel) + { + segment_statistics_.update(p.length, false); + } + else if (allow_3d_arcs_) { + travel_statistics_.update(p.length, false); + } } lines_to_write.append(p.to_string()).append("\n"); } @@ -841,27 +883,12 @@ int arc_welder::write_unwritten_gcodes_to_file() return size; } -std::string arc_welder::get_arc_gcode_relative(double f, const std::string comment) -{ - // Write gcode to file - std::string gcode; - - gcode = current_arc_.get_shape_gcode_relative(f); - - if (comment.length() > 0) - { - gcode += ";" + comment; - } - return gcode; - -} - -std::string arc_welder::get_arc_gcode_absolute(double e, double f, const std::string comment) +std::string arc_welder::get_arc_gcode(const std::string comment) { // Write gcode to file std::string gcode; - gcode = current_arc_.get_shape_gcode_absolute(e, f); + gcode = current_arc_.get_shape_gcode(); if (comment.length() > 0) { diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h index 98564ec..fc5bb84 100644 --- a/ArcWelder/arc_welder.h +++ b/ArcWelder/arc_welder.h @@ -44,9 +44,6 @@ #define _CRT_SECURE_NO_WARNINGS #endif - -#define DEFAULT_G90_G91_INFLUENCES_EXTREUDER false - static const int segment_statistic_lengths_count = 12; const double segment_statistic_lengths[] = { 0.002f, 0.005f, 0.01f, 0.05f, 0.1f, 0.5f, 1.0f, 5.0f, 10.0f, 20.0f, 50.0f, 100.0f }; @@ -346,7 +343,7 @@ private: // Struct to hold the progress, statistics, and return values struct arc_welder_progress { - arc_welder_progress() : segment_statistics(segment_statistic_lengths, segment_statistic_lengths_count, NULL) { + arc_welder_progress() : segment_statistics(segment_statistic_lengths, segment_statistic_lengths_count, NULL), travel_statistics(segment_statistic_lengths, segment_statistic_lengths_count, NULL) { percent_complete = 0.0; seconds_elapsed = 0.0; seconds_remaining = 0.0; @@ -356,6 +353,7 @@ struct arc_welder_progress { arcs_created = 0; arcs_aborted_by_flow_rate = 0; num_firmware_compensations = 0; + num_gcode_length_exceptions = 0; source_file_size = 0; source_file_position = 0; target_file_size = 0; @@ -371,12 +369,30 @@ struct arc_welder_progress { int arcs_created; int arcs_aborted_by_flow_rate; int num_firmware_compensations; + int num_gcode_length_exceptions; double compression_ratio; double compression_percent; long source_file_position; long source_file_size; long target_file_size; source_target_segment_statistics segment_statistics; + source_target_segment_statistics travel_statistics; + + std::string simple_progress_str() const { + std::stringstream stream; + if (percent_complete == 0) { + stream << " 00.0% complete - Estimating remaining time."; + } + else if (percent_complete == 100) + { + stream << "100.0% complete - " << seconds_elapsed << " seconds total."; + } + else { + stream << " " << std::fixed << std::setprecision(1) << std::setfill('0') << std::setw(4) << percent_complete << "% complete - Estimated " << std::setprecision(0) << std::setw(-1) << seconds_remaining << " of " << seconds_elapsed + seconds_remaining << " seconds remaing."; + } + + return stream.str(); + } std::string str() const { std::stringstream stream; @@ -389,19 +405,128 @@ struct arc_welder_progress { stream << ", arcs_created: " << arcs_created; stream << ", arcs_aborted_by_flowrate: " << arcs_aborted_by_flow_rate; stream << ", num_firmware_compensations: " << num_firmware_compensations; + stream << ", num_gcode_length_exceptions: " << num_gcode_length_exceptions; stream << ", compression_ratio: " << compression_ratio; stream << ", size_reduction: " << compression_percent << "% "; return stream.str(); } std::string detail_str() const { std::stringstream stream; - stream << "\n" << "Extrusion/Retraction Counts" << "\n" << segment_statistics.str() << "\n"; + if (travel_statistics.total_count_source > 0) + { + stream << "Target File Travel Statistics:" << "\n" << travel_statistics.str() << "\n"; + } + + stream << "\n" << "Target File Extrusion Statistics:" << "\n" << segment_statistics.str() << "\n"; + return stream.str(); } }; - // define the progress callback type typedef bool(*progress_callback)(arc_welder_progress, logger* p_logger, int logger_type); +// LOGGER_NAME +#define ARC_WELDER_LOGGER_NAME "arc_welder.gcode_conversion" +// Default argument values +#define DEFAULT_G90_G91_INFLUENCES_EXTRUDER false +#define DEFAULT_GCODE_BUFFER_SIZE 10 +#define DEFAULT_G90_G91_INFLUENCES_EXTRUDER false +#define DEFAULT_ALLOW_DYNAMIC_PRECISION false +#define DEFAULT_ALLOW_TRAVEL_ARCS false +#define DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT 0.05 +#define DEFAULT_CONVERT_TRAVEL_MOVES false + + +struct arc_welder_args +{ + arc_welder_args() : + source_path(""), + target_path(""), + log(NULL), + resolution_mm(DEFAULT_RESOLUTION_MM), + path_tolerance_percent(ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT), + max_radius_mm(DEFAULT_MAX_RADIUS_MM), + min_arc_segments(DEFAULT_MIN_ARC_SEGMENTS), + mm_per_arc_segment(DEFAULT_MM_PER_ARC_SEGMENT), + g90_g91_influences_extruder(DEFAULT_G90_G91_INFLUENCES_EXTRUDER), + allow_3d_arcs(DEFAULT_ALLOW_3D_ARCS), + allow_travel_arcs(DEFAULT_ALLOW_TRAVEL_ARCS), + allow_dynamic_precision(DEFAULT_ALLOW_DYNAMIC_PRECISION), + default_xyz_precision(DEFAULT_XYZ_PRECISION), + default_e_precision(DEFAULT_E_PRECISION), + extrusion_rate_variance_percent(DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT), + max_gcode_length(DEFAULT_MAX_GCODE_LENGTH), + buffer_size(DEFAULT_GCODE_BUFFER_SIZE), + callback(NULL){}; + + arc_welder_args(std::string source, std::string target, logger* ptr_log) : arc_welder_args() + { + source_path = source; + target_path = target; + log = ptr_log; + } + std::string source_path; + std::string target_path; + logger* log; + double resolution_mm; + double path_tolerance_percent; + double max_radius_mm; + int min_arc_segments; + double mm_per_arc_segment; + bool g90_g91_influences_extruder; + bool allow_3d_arcs; + bool allow_travel_arcs; + bool allow_dynamic_precision; + unsigned char default_xyz_precision; + unsigned char default_e_precision; + double extrusion_rate_variance_percent; + int buffer_size; + int max_gcode_length; + + progress_callback callback; + + std::string str() const { + std::string log_level_name = "NO_LOGGING"; + if (log != NULL) + { + log_level_name = log->get_log_level_name(ARC_WELDER_LOGGER_NAME); + } + std::stringstream stream; + stream << "Arc Welder Arguments\n"; + stream << std::fixed << std::setprecision(2); + stream << "\tSource File Path : " << source_path << "\n"; + if (source_path == target_path) + { + stream << "\tTarget File Path (overwrite) : " << target_path << "\n"; + } + else + { + stream << "\tTarget File Path : " << target_path << "\n"; + } + stream << "\tResolution : " << resolution_mm << "mm (+-" << std::setprecision(5) << resolution_mm / 2.0 << "mm)\n"; + stream << "\tPath Tolerance : " << std::setprecision(3) << path_tolerance_percent * 100.0 << "%\n"; + stream << "\tMaximum Arc Radius : " << std::setprecision(0) << max_radius_mm << "mm\n"; + stream << "\tMin Arc Segments : " << std::setprecision(0) << min_arc_segments << "\n"; + stream << "\tMM Per Arc Segment : " << std::setprecision(3) << mm_per_arc_segment << "\n"; + stream << "\tAllow 3D Arcs : " << (allow_3d_arcs ? "True" : "False") << "\n"; + stream << "\tAllow Travel Arcs : " << (allow_travel_arcs ? "True" : "False") << "\n"; + stream << "\tAllow Dynamic Precision : " << (allow_dynamic_precision ? "True" : "False") << "\n"; + stream << "\tDefault XYZ Precision : " << std::setprecision(0) << static_cast(default_xyz_precision) << "\n"; + stream << "\tDefault E Precision : " << std::setprecision(0) << static_cast(default_e_precision) << "\n"; + stream << "\tExtrusion Rate Variance % : " << std::setprecision(3) << extrusion_rate_variance_percent * 100.0 << "%\n"; + stream << "\tG90/G91 Influences Extruder : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; + if (max_gcode_length == 0) + { + stream << "\tMax Gcode Length : Unlimited\n"; + } + else { + stream << "\tMax Gcode Length : " << std::setprecision(0) << max_gcode_length << " characters\n"; + } + stream << "\tLog Level : " << log_level_name << "\n"; + stream << "\tHide Progress Updates : " << (callback == NULL ? "True" : "False"); + return stream.str(); + }; + +}; struct arc_welder_results { arc_welder_results() : progress() @@ -415,12 +540,7 @@ struct arc_welder_results { std::string message; arc_welder_progress progress; }; -#define DEFAULT_GCODE_BUFFER_SIZE 10 -#define DEFAULT_G90_G91_INFLUENCES_EXTRUDER false -#define DEFAULT_ALLOW_DYNAMIC_PRECISION false -#define DEFAULT_ALLOW_TRAVEL_ARCS false -#define DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT 0.05 -#define DEFAULT_CONVERT_TRAVEL_MOVES false + class arc_welder { public: @@ -440,8 +560,32 @@ public: unsigned char default_xyz_precision, unsigned char default_e_precision, double extrusion_rate_variance_percent, + int max_gcode_length, int buffer_size, progress_callback callback); + + arc_welder(arc_welder_args args) : arc_welder( + args.source_path, + args.target_path, + args.log, + args.resolution_mm, + args.path_tolerance_percent, + args.max_radius_mm, + args.min_arc_segments, + args.mm_per_arc_segment, + args.g90_g91_influences_extruder, + args.allow_3d_arcs, + args.allow_travel_arcs, + args.allow_dynamic_precision, + args.default_xyz_precision, + args.default_e_precision, + args.extrusion_rate_variance_percent, + args.max_gcode_length, + args.buffer_size, + args.callback + ){}; + + void set_logger_type(int logger_type); virtual ~arc_welder(); arc_welder_results process(); @@ -455,10 +599,9 @@ private: static gcode_position_args get_args_(bool g90_g91_influences_extruder, int buffer_size); progress_callback progress_callback_; int process_gcode(parsed_command cmd, bool is_end, bool is_reprocess); - void write_arc_gcodes(bool is_extruder_relative, double current_feedrate); + void write_arc_gcodes(double current_feedrate); int write_gcode_to_file(std::string gcode); - std::string get_arc_gcode_relative(double f, const std::string comment); - std::string get_arc_gcode_absolute(double e, double f, const std::string comment); + std::string get_arc_gcode(const std::string comment); std::string get_comment_for_arc(); int write_unwritten_gcodes_to_file(); std::string create_g92_e(double absolute_e); @@ -477,6 +620,7 @@ private: int arcs_created_; int arcs_aborted_by_flow_rate_; source_target_segment_statistics segment_statistics_; + source_target_segment_statistics travel_statistics_; long get_file_size(const std::string& file_path); double get_time_elapsed(double start_clock, double end_clock); double get_next_update_time() const; diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp index 51ef57e..531c9e5 100644 --- a/ArcWelder/segmented_arc.cpp +++ b/ArcWelder/segmented_arc.cpp @@ -38,7 +38,10 @@ segmented_arc::segmented_arc() : segmented_shape(DEFAULT_MIN_SEGMENTS, DEFAULT_M min_arc_segments_ = DEFAULT_MIN_ARC_SEGMENTS, mm_per_arc_segment_ = DEFAULT_MM_PER_ARC_SEGMENT; allow_3d_arcs_ = DEFAULT_ALLOW_3D_ARCS; + max_gcode_length_ = DEFAULT_MAX_GCODE_LENGTH; + num_gcode_length_exceptions_ = 0; num_firmware_compensations_ = 0; + } segmented_arc::segmented_arc( @@ -51,7 +54,8 @@ segmented_arc::segmented_arc( double mm_per_arc_segment, bool allow_3d_arcs, unsigned char default_xyz_precision, - unsigned char default_e_precision + unsigned char default_e_precision, + int max_gcode_length ) : segmented_shape(min_segments, max_segments, resolution_mm, path_tolerance_percent, default_xyz_precision, default_e_precision) { max_radius_mm_ = max_radius_mm; @@ -69,7 +73,15 @@ segmented_arc::segmented_arc( min_arc_segments_ = 0; } allow_3d_arcs_ = allow_3d_arcs; + max_gcode_length_ = max_gcode_length; + if (max_gcode_length_ < 1) + { + max_gcode_length_ = 0; + } num_firmware_compensations_ = 0; + num_gcode_length_exceptions_ = 0; + + } segmented_arc::~segmented_arc() @@ -108,7 +120,10 @@ int segmented_arc::get_num_firmware_compensations() const { return num_firmware_compensations_; } - +int segmented_arc::get_num_gcode_length_exceptions() const +{ + return num_gcode_length_exceptions_; +} double segmented_arc::get_mm_per_arc_segment() const { return mm_per_arc_segment_; @@ -143,7 +158,7 @@ bool segmented_arc::try_add_point(printer_point p) } // Need to separate travel moves from moves with extrusion - if (points_.count() > 2) + if (points_.count() > 1) { // We already have at least an initial point and a second point. Make cure the current point and the previous are either both // travel moves, or both extrusion @@ -217,6 +232,11 @@ bool segmented_arc::try_add_point_internal_(printer_point p) if (arc::try_create_arc(points_, current_arc_, original_shape_length_, max_radius_mm_, resolution_mm_, path_tolerance_percent_, min_arc_segments_, mm_per_arc_segment_, get_xyz_tolerance(), allow_3d_arcs_)) { bool abort_arc = false; + if (max_gcode_length_ > 0 && get_shape_gcode_length() > max_gcode_length_) + { + abort_arc = true; + num_gcode_length_exceptions_++; + } if (min_arc_segments_ > 0 && mm_per_arc_segment_ > 0) { // Apply firmware compensation @@ -252,7 +272,7 @@ bool segmented_arc::try_add_point_internal_(printer_point p) // or because both I and J == 0 current_arc_ = original_arc; } - else if (!abort_arc) + else { if (!is_shape()) { @@ -267,22 +287,12 @@ bool segmented_arc::try_add_point_internal_(printer_point p) return false; } -std::string segmented_arc::get_shape_gcode_absolute(double e, double f) -{ - bool has_e = e_relative_ != 0; - return get_shape_gcode_(has_e, e, f); -} - -std::string segmented_arc::get_shape_gcode_relative(double f) -{ - bool has_e = e_relative_ != 0; - return get_shape_gcode_(has_e, e_relative_, f); -} - -std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f) const +std::string segmented_arc::get_shape_gcode() const { std::string gcode; - // Calculate gcode size + double e = current_arc_.end_point.is_extruder_relative ? e_relative_ : current_arc_.end_point.e_offset; + double f = current_arc_.start_point.f == current_arc_.end_point.f ? 0 : current_arc_.end_point.f; + bool has_e = e_relative_ != 0; bool has_f = utilities::greater_than_or_equal(f, 1); bool has_z = allow_3d_arcs_ && !utilities::is_equal( current_arc_.start_point.z, current_arc_.end_point.z, get_xyz_tolerance() @@ -298,6 +308,9 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f) cons gcode += "G3"; } + // TODO: Limit Gcode Precision based on max_gcode_length + + // Add X, Y, I and J gcode += " X"; gcode += utilities::dtos(current_arc_.end_point.x, get_xyz_precision()); @@ -338,6 +351,40 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f) cons return gcode; +} + +int segmented_arc::get_shape_gcode_length() +{ + double e = current_arc_.end_point.is_extruder_relative ? e_relative_ : current_arc_.end_point.e_offset; + double f = current_arc_.start_point.f == current_arc_.end_point.f ? 0 : current_arc_.end_point.f; + bool has_e = e_relative_ != 0; + bool has_f = utilities::greater_than_or_equal(f, 1); + bool has_z = allow_3d_arcs_ && !utilities::is_equal( + current_arc_.start_point.z, current_arc_.end_point.z, get_xyz_tolerance() + ); + + int xyz_precision = get_xyz_precision(); + int e_precision = get_e_precision(); + + double i = current_arc_.get_i(); + double j = current_arc_.get_j(); + + int num_spaces = 3 + (has_z ? 1 : 0) + (has_e ? 1 : 0) + (has_f ? 1 : 0); + int num_decimal_points = 4 + (has_z ? 1 : 0) + (has_e ? 1 : 0); // note f has no decimal point + int num_decimals = xyz_precision * (4 + (has_z ? 1 : 0) + (has_e ? 1 : 0)); // Note f is an int + int num_digits = ( + utilities::get_num_digits(current_arc_.end_point.x) + + utilities::get_num_digits(current_arc_.end_point.y) + + (has_z ? utilities::get_num_digits(current_arc_.end_point.z) : 0) + + utilities::get_num_digits(i) + + utilities::get_num_digits(j) + + (has_f ? utilities::get_num_digits(f) : 0) + ); + // Return the length of the gcode. + return 3 + num_spaces + num_decimal_points + num_decimal_points + num_digits; + + + } /* diff --git a/ArcWelder/segmented_arc.h b/ArcWelder/segmented_arc.h index c67c071..2c7b240 100644 --- a/ArcWelder/segmented_arc.h +++ b/ArcWelder/segmented_arc.h @@ -42,14 +42,14 @@ public: double mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT, bool allow_3d_arcs = DEFAULT_ALLOW_3D_ARCS, unsigned char default_xyz_precision = DEFAULT_XYZ_PRECISION, - unsigned char default_e_precision = DEFAULT_E_PRECISION + unsigned char default_e_precision = DEFAULT_E_PRECISION, + int max_gcode_length = DEFAULT_MAX_GCODE_LENGTH ); virtual ~segmented_arc(); virtual bool try_add_point(printer_point p); virtual double get_shape_length(); - std::string get_shape_gcode_absolute(double e, double f); - std::string get_shape_gcode_relative(double f); - + std::string get_shape_gcode() const; + int get_shape_gcode_length(); virtual bool is_shape() const; printer_point pop_front(double e_relative); printer_point pop_back(double e_relative); @@ -57,15 +57,16 @@ public: int get_min_arc_segments() const; double get_mm_per_arc_segment() const; int get_num_firmware_compensations() const; - + int get_num_gcode_length_exceptions() const; private: bool try_add_point_internal_(printer_point p); - std::string get_shape_gcode_(bool has_e, double e, double f) const; arc current_arc_; double max_radius_mm_; int min_arc_segments_; double mm_per_arc_segment_; int num_firmware_compensations_; bool allow_3d_arcs_; + int max_gcode_length_; + int num_gcode_length_exceptions_; }; diff --git a/ArcWelder/segmented_shape.cpp b/ArcWelder/segmented_shape.cpp index 4e17d3c..447cfbe 100644 --- a/ArcWelder/segmented_shape.cpp +++ b/ArcWelder/segmented_shape.cpp @@ -359,7 +359,7 @@ bool circle::is_over_deviation(const array_list& points, const do double distance = utilities::get_cartesian_distance(point_to_test.x, point_to_test.y, center.x, center.y); if (std::fabs(distance - radius) > resolution_mm) { - return true; + return true; } } } @@ -380,9 +380,9 @@ double arc::get_j() const bool arc::try_create_arc( const circle& c, - const point& start_point, - const point& mid_point, - const point& end_point, + const printer_point& start_point, + const printer_point& mid_point, + const printer_point& end_point, arc& target_arc, double approximate_length, double resolution, diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h index ec4bde9..d6e7218 100644 --- a/ArcWelder/segmented_shape.h +++ b/ArcWelder/segmented_shape.h @@ -36,7 +36,7 @@ #define DEFAULT_XYZ_TOLERANCE 0.001 #define DEFAULT_E_PRECISION 5 #define ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT 0.05 // one percent - +#define DEFAULT_MAX_GCODE_LENGTH 0 // the maximum gcode length ( < 1 = unlimited) struct point { public: @@ -53,9 +53,13 @@ public: struct printer_point : point { public: - printer_point() :point(0, 0, 0), e_relative(0), distance(0) {} - printer_point(double x, double y, double z, double e_relative, double distance) :point(x,y,z), e_relative(e_relative), distance(distance) {} + printer_point() :point(0, 0, 0), e_relative(0), distance(0), is_extruder_relative(false), e_offset(0), f(0) {} + printer_point(double x, double y, double z, double e_offset, double e_relative, double f, double distance, bool is_extruder_relative) + : point(x,y,z), e_offset(e_offset), e_relative(e_relative), f(f), distance(distance), is_extruder_relative(is_extruder_relative) {} + bool is_extruder_relative; + double e_offset; double e_relative; + double f; double distance; }; @@ -164,8 +168,8 @@ struct arc : circle double polar_start_theta; double polar_end_theta; double max_deviation; - point start_point; - point end_point; + printer_point start_point; + printer_point end_point; DirectionEnum direction; double get_i() const; double get_j() const; @@ -185,9 +189,9 @@ struct arc : circle private: static bool try_create_arc( const circle& c, - const point& start_point, - const point& mid_point, - const point& end_point, + const printer_point& start_point, + const printer_point& mid_point, + const printer_point& end_point, arc& target_arc, double approximate_length, double resolution = DEFAULT_RESOLUTION_MM, diff --git a/ArcWelder/unwritten_command.h b/ArcWelder/unwritten_command.h index 8f85a50..d1ed490 100644 --- a/ArcWelder/unwritten_command.h +++ b/ArcWelder/unwritten_command.h @@ -29,34 +29,18 @@ struct unwritten_command { unwritten_command() { is_extruder_relative = false; - e_relative = 0; - offset_e = 0; - extrusion_length = 0; - is_g1_g2 = false; + length = 0; + is_g0_g1 = false; } - unwritten_command(parsed_command &cmd, bool is_relative, double command_length) { - is_extruder_relative = is_relative; - is_g1_g2 = cmd.command == "G0" || cmd.command == "G1"; - gcode = cmd.gcode; - comment = cmd.comment; - extrusion_length = command_length; + unwritten_command(parsed_command &cmd, bool is_relative, bool is_travel, double command_length) + : is_extruder_relative(is_relative), is_travel(is_travel), is_g0_g1(cmd.command == "G0" || cmd.command == "G1"), gcode(cmd.gcode), comment(cmd.comment), length(command_length) + { + } - /* - unwritten_command(position* p, double command_length) { - - e_relative = p->get_current_extruder().e_relative; - offset_e = p->get_current_extruder().get_offset_e(); - is_extruder_relative = p->is_extruder_relative; - is_g1_g2 = p->command.command == "G0" || p->command.command == "G1"; - gcode = p->command.gcode; - comment = p->command.comment; - extrusion_length = command_length; - } */ - bool is_g1_g2; + bool is_g0_g1; bool is_extruder_relative; - double e_relative; - double offset_e; - double extrusion_length; + bool is_travel; + double length; std::string gcode; std::string comment; -- cgit v1.2.3