diff options
Diffstat (limited to 'ArcWelder/arc_welder.h')
-rw-r--r-- | ArcWelder/arc_welder.h | 374 |
1 files changed, 320 insertions, 54 deletions
diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h index 6d00ec4..c7d7465 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 }; @@ -64,7 +61,8 @@ struct segment_statistic { }; struct source_target_segment_statistics { - source_target_segment_statistics(const double segment_tracking_lengths[], const int num_lengths, logger* p_logger = NULL) { + source_target_segment_statistics(const double segment_tracking_lengths[], const int num_lengths, logger* p_logger = NULL) + { total_length_source = 0; total_length_target = 0; total_count_source = 0; @@ -76,6 +74,7 @@ struct source_target_segment_statistics { for (int index = 0; index < num_lengths; index++) { double current_max = segment_tracking_lengths[index]; + segment_statistic_lengths.push_back(segment_tracking_lengths[index]); source_segments.push_back(segment_statistic(current_min, segment_tracking_lengths[index])); target_segments.push_back(segment_statistic(current_min, segment_tracking_lengths[index])); current_min = current_max; @@ -86,7 +85,8 @@ struct source_target_segment_statistics { p_logger_ = p_logger; logger_type_ = 0; } - + + std::vector<double> segment_statistic_lengths; std::vector<segment_statistic> source_segments; std::vector<segment_statistic> target_segments; double total_length_source; @@ -96,7 +96,7 @@ struct source_target_segment_statistics { int total_count_source; int total_count_target; int num_segment_tracking_lengths; - + double get_total_count_reduction_percent() const { return utilities::get_percent_change(total_count_source, total_count_target); } @@ -130,10 +130,49 @@ struct source_target_segment_statistics { } } + static source_target_segment_statistics add(source_target_segment_statistics stats1, const source_target_segment_statistics stats2) + { + + double * lengths = &stats1.segment_statistic_lengths[0]; + std::copy(stats1.segment_statistic_lengths.begin(), stats1.segment_statistic_lengths.end(), lengths); + source_target_segment_statistics combined_stats(lengths, segment_statistic_lengths_count, stats1.p_logger_); + if (stats1.num_segment_tracking_lengths != stats2.num_segment_tracking_lengths) + { + // Todo: throw a reasonable exception + throw std::exception(); + } + + // Copy the segment statistics + for (int index = 0; index <= stats1.num_segment_tracking_lengths; index++) + { + // Verify the stats are the same + if ( + stats1.source_segments[index].min_mm != stats2.source_segments[index].min_mm + || stats1.source_segments[index].max_mm != stats2.source_segments[index].max_mm + ) + { + // Todo: throw a reasonable exception + throw std::exception(); + } + combined_stats.source_segments[index].count = stats1.source_segments[index].count + stats2.source_segments[index].count; + combined_stats.target_segments[index].count = stats1.target_segments[index].count + stats2.target_segments[index].count; + } + + combined_stats.total_length_source = stats1.total_length_source + stats2.total_length_source; + combined_stats.total_length_target = stats1.total_length_target + stats2.total_length_target; + combined_stats.total_count_source = stats1.total_count_source + stats2.total_count_source; + combined_stats.total_count_target = stats1.total_count_target + stats2.total_count_target; + + return combined_stats; + } std::string str() const { + return str("", utilities::box_drawing::BoxEncodingEnum::ASCII); + } + + std::string str(std::string title, utilities::box_drawing::BoxEncodingEnum box_encoding) const { //if (p_logger_ != NULL) p_logger_->log(logger_type_, VERBOSE, "Building Segment Statistics."); - + std::stringstream output_stream; std::stringstream format_stream; const int min_column_size = 8; @@ -210,21 +249,51 @@ struct source_target_segment_statistics { } // Get the table width int table_width = mm_col_size + min_max_label_col_size + mm_col_size + source_col_size + target_col_size + percent_col_size; - // Add a separator for the statistics - //output_stream << std::setw(table_width) << std::setfill('-') << "-" << "\n" << std::setfill(' ') ; - // Output the column headers - // Center the min and max column. - output_stream << utilities::center("Min", mm_col_size); + int table_left_padding = 0; + int table_right_padding = 0; + if (table_width < (int)title.length()) + { + table_left_padding = ((int)title.length() - table_width) / 2; + table_right_padding = ((int)title.length() - table_width - table_left_padding); + table_width = (int)title.length(); + + } + utilities::box_drawing box(box_encoding, table_width); + // Draw the top border + box.top(output_stream); + + if (title != "") + { + // Draw the title + box.row(output_stream, utilities::center(title, table_width)); + // Draw the title separator + box.middle(output_stream); + } + + // Output the centered column headers + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); + // add the left padding for the table + output_stream << std::string(table_left_padding, ' '); + output_stream << std::setfill(' ') << utilities::center("Min", mm_col_size); output_stream << std::setw(min_max_label_col_size) << ""; output_stream << utilities::center("Max", mm_col_size); // right align the source, target and change columns output_stream << std::setw(source_col_size) << std::right << "Source"; output_stream << std::setw(target_col_size) << std::right << "Target"; output_stream << std::setw(percent_col_size) << std::right << "Change"; - output_stream << "\n"; - output_stream << std::setw(table_width) << std::setfill('-') << "" << std::setfill(' ') << "\n"; + // Add the right padding for the table + output_stream << std::string(table_right_padding, ' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; output_stream << std::fixed << std::setprecision(max_precision); + // Add the separator + box.middle(output_stream); for (int index = 0; index < source_segments.size(); index++) { + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); + // add the left padding for the table + output_stream << std::string(table_left_padding, ' '); //extract the necessary variables from the source and target segments double min_mm = source_segments[index].min_mm; double max_mm = source_segments[index].max_mm; @@ -287,24 +356,34 @@ struct source_target_segment_statistics { output_stream << std::setw(target_col_size) << target_count_string; // Add the percent change string output_stream << std::setw(percent_col_size) << percent_change_string; - // End the line - output_stream << "\n"; + // Add the right padding for the table + output_stream << std::string(table_right_padding, ' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; } - // Add the total rows separator - output_stream << std::setw(table_width) << std::setfill('-') << "" << std::setfill(' ') << "\n"; + + // Add the total rows; + // Draw the totals separator + box.middle(output_stream); if (utilities::is_equal(total_length_source, total_length_target, 0.001)) { + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); std::string total_distance_string; format_stream.str(std::string()); format_stream << std::fixed << std::setprecision(max_precision) << total_length_source << "mm"; total_distance_string = format_stream.str(); output_stream << std::setw(totals_row_label_size) << std::right << "Total distance:"; - output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_distance_string << "\n" << std::setfill(' '); + output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_distance_string << std::setfill(' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; } else { - // We need to output two different distances (this probably should never happen) + // We need to output two different distances + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); // Format the total source distance string std::string total_source_distance_string; format_stream.str(std::string()); @@ -312,8 +391,12 @@ struct source_target_segment_statistics { total_source_distance_string = format_stream.str(); // Add the total source distance row output_stream << std::setw(totals_row_label_size) << std::right << "Total distance source:"; - output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_source_distance_string << "\n" << std::setfill(' '); + output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_source_distance_string << std::setfill(' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); // Format the total target distance string std::string total_target_distance_string; format_stream.str(std::string()); @@ -321,32 +404,55 @@ struct source_target_segment_statistics { total_target_distance_string = format_stream.str(); // Add the total target distance row output_stream << std::setw(totals_row_label_size) << std::right << "Total distance target:"; - output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_target_distance_string << "\n" << std::setfill(' '); + output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_target_distance_string << std::setfill(' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; } // Add the total count rows + + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); // Add the source count output_stream << std::setprecision(0) << std::setw(totals_row_label_size) << std::right << "Total count source:"; - output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_count_source << "\n" << std::setfill(' '); + output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_count_source << std::setfill(' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; + + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); // Add the target count output_stream << std::setw(totals_row_label_size) << std::right << "Total count target:"; - output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_count_target << "\n" << std::setfill(' '); + output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_count_target << std::setfill(' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; + + // start the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL); // Add the total percent change row std::string total_percent_change_string = utilities::get_percent_change_string(total_count_source, total_count_target, 1); output_stream << std::setw(totals_row_label_size) << std::right << "Total percent change:"; output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_percent_change_string << std::setfill(' '); + // end the row + output_stream << box.get_box_replacement_element(utilities::box_drawing::BoxElementEnum::VERTICAL) << "\n"; + + // Add the final separator + box.bottom(output_stream); + std::string output_string = output_stream.str(); + box.make_replacements(output_string); return output_string; } private: + logger* p_logger_; int logger_type_; }; // 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), segment_retraction_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; @@ -354,12 +460,16 @@ struct arc_welder_progress { lines_processed = 0; points_compressed = 0; 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; compression_ratio = 0; compression_percent = 0; + combine_extrusion_and_retraction = true; + box_encoding = utilities::box_drawing::BoxEncodingEnum::ASCII; } double percent_complete; double seconds_elapsed; @@ -368,15 +478,39 @@ struct arc_welder_progress { int lines_processed; int points_compressed; 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; + bool combine_extrusion_and_retraction; + utilities::box_drawing::BoxEncodingEnum box_encoding; + source_target_segment_statistics segment_statistics; + source_target_segment_statistics segment_retraction_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; stream << std::fixed << std::setprecision(2); @@ -385,20 +519,159 @@ struct arc_welder_progress { stream << ", current_file_line: " << lines_processed; stream << ", points_compressed: " << points_compressed; 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 << "% "; + 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"; - return stream.str(); + std::stringstream wstream; + wstream << "\n"; + + if (travel_statistics.total_count_source > 0) + { + wstream << travel_statistics.str("Target File Travel Statistics", box_encoding) << "\n"; + } + + if (combine_extrusion_and_retraction) + { + source_target_segment_statistics combined_stats = source_target_segment_statistics::add(segment_statistics, segment_retraction_statistics); + wstream << combined_stats.str("Target File Extrusion/Retraction Statistics", box_encoding) << "\n"; + } + else + { + + if (segment_retraction_statistics.total_count_source > 0) + { + wstream << segment_retraction_statistics.str("Target File Retraction Statistics", box_encoding) << "\n"; + } + + wstream << segment_statistics.str("Target File Extrusion Statistics", box_encoding) << "\n"; + } + return wstream.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 true +#define DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT 0.05 +#define DEFAULT_NOTIFICATION_PERIOD_SECONDS 0.5 + +struct arc_welder_args +{ + arc_welder_args() { + set_defaults(); + }; + + + arc_welder_args(std::string source, std::string target, logger* ptr_log) + { + set_defaults(); + 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; + double notification_period_seconds; + utilities::box_drawing::BoxEncodingEnum box_encoding; + + 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<int>(default_xyz_precision) << "\n"; + stream << "\tDefault E Precision : " << std::setprecision(0) << static_cast<int>(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") << "\n"; + stream << "\tProgress Notification Period : " << std::setprecision(2) << notification_period_seconds << " seconds"; + return stream.str(); + }; + +private: + void set_defaults() + { + 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, + notification_period_seconds = DEFAULT_NOTIFICATION_PERIOD_SECONDS, + callback = NULL; + box_encoding = utilities::box_drawing::BoxEncodingEnum::ASCII; + } + +}; struct arc_welder_results { arc_welder_results() : progress() @@ -412,45 +685,31 @@ struct arc_welder_results { std::string message; arc_welder_progress progress; }; -#define DEFAULT_GCODE_BUFFER_SIZE 1000 -#define DEFAULT_G90_G91_INFLUENCES_EXTRUDER false -#define DEFAULT_ALLOW_DYNAMIC_PRECISION false + class arc_welder { public: - arc_welder( - std::string source_path, - std::string target_path, - logger* log, - double resolution_mm, - double path_tolerance_percent, - double max_radius, - int min_arc_segments, - double mm_per_arc_segment, - bool g90_g91_influences_extruder = DEFAULT_G90_G91_INFLUENCES_EXTRUDER, - bool allow_3d_arcs = DEFAULT_ALLOW_3D_ARCS, - bool allow_dynamic_precision = DEFAULT_ALLOW_DYNAMIC_PRECISION, - unsigned char default_xyz_precision = DEFAULT_XYZ_PRECISION, - unsigned char default_e_precision = DEFAULT_E_PRECISION, - int buffer_size = DEFAULT_GCODE_BUFFER_SIZE, - progress_callback callback = NULL); + + arc_welder(arc_welder_args args); + + void set_logger_type(int logger_type); virtual ~arc_welder(); arc_welder_results process(); - double notification_period_seconds; + protected: virtual bool on_progress_(const arc_welder_progress& progress); private: + arc_welder_progress get_progress_(long source_file_position, double start_clock); void add_arcwelder_comment_to_target(); void reset(); 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); @@ -460,13 +719,18 @@ private: gcode_position_args gcode_position_args_; bool allow_dynamic_precision_; bool allow_3d_arcs_; + bool allow_travel_arcs_; long file_size_; int lines_processed_; int gcodes_processed_; int last_gcode_line_written_; int points_compressed_; int arcs_created_; + int arcs_aborted_by_flow_rate_; + double notification_period_seconds_; source_target_segment_statistics segment_statistics_; + source_target_segment_statistics segment_retraction_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; @@ -478,6 +742,8 @@ private: // We don't care about the printer settings, except for g91 influences extruder. gcode_position* p_source_position_; double previous_feedrate_; + double previous_extrusion_rate_; + double extrusion_rate_variance_percent_; gcode_parser parser_; bool verbose_output_; int logger_type_; @@ -486,5 +752,5 @@ private: bool info_logging_enabled_; bool verbose_logging_enabled_; bool error_logging_enabled_; - + utilities::box_drawing::BoxEncodingEnum box_encoding_; }; |