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 +-- ArcWelderConsole/ArcWelderConsole.cpp | 258 ++++++++-------- ArcWelderConsole/ArcWelderConsole.h | 6 +- ArcWelderTest/ArcWelderTest.cpp | 46 +-- ArcWelderTest/ArcWelderTest.h | 2 +- GcodeProcessorLib/logger.cpp | 14 + GcodeProcessorLib/logger.h | 5 +- GcodeProcessorLib/utilities.cpp | 2 +- GcodeProcessorLib/utilities.h | 1 - PyArcWelder/py_arc_welder.cpp | 507 ++++++++++++++++++++++++++------ PyArcWelder/py_arc_welder.h | 63 ++-- PyArcWelder/py_arc_welder_extension.cpp | 257 +--------------- PyArcWelder/py_arc_welder_extension.h | 71 +---- 19 files changed, 947 insertions(+), 782 deletions(-) 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; diff --git a/ArcWelderConsole/ArcWelderConsole.cpp b/ArcWelderConsole/ArcWelderConsole.cpp index 16a6923..e7a1ea9 100644 --- a/ArcWelderConsole/ArcWelderConsole.cpp +++ b/ArcWelderConsole/ArcWelderConsole.cpp @@ -34,27 +34,19 @@ #include #define DEFAULT_ARG_DOUBLE_PRECISION 4 +#define PROGRESS_TYPE_NONE "NONE" +#define PROGRESS_TYPE_SIMPLE "SIMPLE" +#define PROGRESS_TYPE_FULL "FULL" int main(int argc, char* argv[]) { - std::string source_file_path; - std::string target_file_path; - double resolution_mm; - double max_radius_mm; - int min_arc_segments; - double mm_per_arc_segment; - double path_tolerance_percent; - bool g90_g91_influences_extruder; - bool hide_progress; - bool overwrite_source_file = false; - bool allow_3d_arcs = DEFAULT_ALLOW_3D_ARCS; - bool allow_travel_arcs = DEFAULT_ALLOW_TRAVEL_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; - double extrusion_rate_variance_percent = DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT; + + arc_welder_args args; std::string log_level_string; std::string log_level_string_default = "INFO"; + std::string progress_type; + std::string progress_type_default_string = PROGRESS_TYPE_SIMPLE; int log_level_value; + bool hide_progress = false; // Add info about the application std::string info = "Arc Welder: Anti-Stutter - Reduces the number of gcodes per second sent to a 3D printer that supports arc commands (G2 G3)."; @@ -154,9 +146,24 @@ int main(int argc, char* argv[]) arg_description_stream << "(experimental) - The allowed variance in extrusion rate by percent. Default Value: " << DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT; TCLAP::ValueArg extrusion_rate_variance_percent_arg("v", "extrusion-rate-variance-percent", arg_description_stream.str(), false, DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT, "double"); + // -l --max-gcode-length + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The maximum length allowed for a generated G2/G3 command, not including any comments. 0 = no limit. Default Value: " << DEFAULT_MAX_GCODE_LENGTH; + TCLAP::ValueArg max_gcode_length_arg("l", "max-gcode-length", arg_description_stream.str(), false, DEFAULT_MAX_GCODE_LENGTH, "int"); - // -g --hide-progress - TCLAP::SwitchArg hide_progress_arg("p", "hide-progress", "If supplied, prevents progress updates from being displayed.", false); + // -p --progress-type + // -l --log-level + std::vector progress_type_vector; + std::string progress_type_default_string = PROGRESS_TYPE_SIMPLE; + progress_type_vector.push_back(PROGRESS_TYPE_NONE); + progress_type_vector.push_back(PROGRESS_TYPE_SIMPLE); + progress_type_vector.push_back(PROGRESS_TYPE_FULL); + TCLAP::ValuesConstraint progress_type_constraint(progress_type_vector); + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Sets the progress type display. Default Value " << progress_type_default_string; + TCLAP::ValueArg progress_type_arg("p", "progress-type", arg_description_stream.str(), false, progress_type_default_string, &progress_type_constraint); // -l --log-level std::vector log_levels_vector; @@ -188,117 +195,125 @@ int main(int argc, char* argv[]) cmd.add(default_xyz_precision_arg); cmd.add(default_e_precision_arg); cmd.add(extrusion_rate_variance_percent_arg); + cmd.add(max_gcode_length_arg); cmd.add(g90_arg); - cmd.add(hide_progress_arg); + cmd.add(progress_type_arg); cmd.add(log_level_arg); // Parse the argv array. cmd.parse(argc, argv); // Get the value parsed by each arg. - source_file_path = source_arg.getValue(); - target_file_path = target_arg.getValue(); + args.source_path = source_arg.getValue(); + args.target_path = target_arg.getValue(); - if (target_file_path.size() == 0) + if (args.target_path.size() == 0) { - target_file_path = source_file_path; + args.target_path = args.source_path; } - resolution_mm = resolution_arg.getValue(); - max_radius_mm = max_radius_arg.getValue(); - min_arc_segments = min_arc_segments_arg.getValue(); - mm_per_arc_segment = mm_per_arc_segment_arg.getValue(); - path_tolerance_percent = path_tolerance_percent_arg.getValue(); - allow_3d_arcs = allow_3d_arcs_arg.getValue(); - allow_travel_arcs = allow_travel_arcs_arg.getValue(); - g90_g91_influences_extruder = g90_arg.getValue(); - allow_dynamic_precision = allow_dynamic_precision_arg.getValue(); - default_xyz_precision = default_xyz_precision_arg.getValue(); - default_e_precision = default_e_precision_arg.getValue(); - extrusion_rate_variance_percent = extrusion_rate_variance_percent_arg.getValue(); - - hide_progress = hide_progress_arg.getValue(); + args.resolution_mm = resolution_arg.getValue(); + args.max_radius_mm = max_radius_arg.getValue(); + args.min_arc_segments = min_arc_segments_arg.getValue(); + args.mm_per_arc_segment = mm_per_arc_segment_arg.getValue(); + args.path_tolerance_percent = path_tolerance_percent_arg.getValue(); + args.allow_3d_arcs = allow_3d_arcs_arg.getValue(); + args.allow_travel_arcs = allow_travel_arcs_arg.getValue(); + args.g90_g91_influences_extruder = g90_arg.getValue(); + args.allow_dynamic_precision = allow_dynamic_precision_arg.getValue(); + args.default_xyz_precision = default_xyz_precision_arg.getValue(); + args.default_e_precision = default_e_precision_arg.getValue(); + args.extrusion_rate_variance_percent = extrusion_rate_variance_percent_arg.getValue(); + args.max_gcode_length = max_gcode_length_arg.getValue(); + progress_type = progress_type_arg.getValue(); log_level_string = log_level_arg.getValue(); log_level_value = -1; // Check the entered values bool has_error = false; - if (resolution_mm <= 0) + if (args.resolution_mm <= 0) { - std::cerr << "error: The provided resolution of " << resolution_mm << " is negative, which is not allowed." < 1000000) + if (args.max_radius_mm > 1000000) { // warning - std::cout << "warning: The provided path max radius of " << max_radius_mm << "mm is greater than 1000000 (1km), which is not recommended." << std::endl; + std::cout << "warning: The provided path max radius of " << args.max_radius_mm << "mm is greater than 1000000 (1km), which is not recommended." << std::endl; } - if (min_arc_segments < 0) + if (args.min_arc_segments < 0) { // warning - std::cout << "warning: The provided min_arc_segments " << min_arc_segments << " is less than zero. Setting to 0." << std::endl; - min_arc_segments = 0; + std::cout << "warning: The provided min_arc_segments " << args.min_arc_segments << " is less than zero. Setting to 0." << std::endl; + args.min_arc_segments = 0; } - if (mm_per_arc_segment < 0) + if (args.mm_per_arc_segment < 0) { // warning - std::cout << "warning: The provided mm_per_arc_segment " << mm_per_arc_segment << "mm is less than zero. Setting to 0." << std::endl; - mm_per_arc_segment = 0; + std::cout << "warning: The provided mm_per_arc_segment " << args.mm_per_arc_segment << "mm is less than zero. Setting to 0." << std::endl; + args.mm_per_arc_segment = 0; } - if (path_tolerance_percent > 0.05) + if (args.path_tolerance_percent > 0.05) { // warning - std::cout << "warning: The provided path tolerance percent of " << path_tolerance_percent << " is greater than 0.05 (5%), which is not recommended." << std::endl; + std::cout << "warning: The provided path tolerance percent of " << args.path_tolerance_percent << " is greater than 0.05 (5%), which is not recommended." << std::endl; } - else if (path_tolerance_percent < 0.0001 && path_tolerance_percent > 0) + else if (args.path_tolerance_percent < 0.0001 && args.path_tolerance_percent > 0) { // warning - std::cout << "warning: The provided path tolerance percent of " << path_tolerance_percent << " is less than greater than 0.001 (0.1%), which is not recommended." << std::endl; + std::cout << "warning: The provided path tolerance percent of " << args.path_tolerance_percent << " is less than greater than 0.001 (0.1%), which is not recommended." << std::endl; } - if (default_xyz_precision < 3) + if (args.default_xyz_precision < 3) { // warning - std::cout << "warning: The provided default_xyz_precision " << default_xyz_precision << "mm is less than 3, with will cause issues printing arcs. A value of 3 will be used instead." << std::endl; - default_xyz_precision = 3; + std::cout << "warning: The provided default_xyz_precision " << args.default_xyz_precision << "mm is less than 3, with will cause issues printing arcs. A value of 3 will be used instead." << std::endl; + args.default_xyz_precision = 3; } - if (default_e_precision < DEFAULT_E_PRECISION) + if (args.default_e_precision < DEFAULT_E_PRECISION) { // warning - std::cout << "warning: The provided default_e_precision " << default_e_precision << "mm is less than 3, with will cause extrusion issues. A value of 3 will be used instead." << std::endl; - default_e_precision = 3; + std::cout << "warning: The provided default_e_precision " << args.default_e_precision << "mm is less than 3, with will cause extrusion issues. A value of 3 will be used instead." << std::endl; + args.default_e_precision = 3; } - if (default_xyz_precision > 6) + if (args.default_xyz_precision > 6) { // warning - std::cout << "warning: The provided default_xyz_precision " << default_xyz_precision << "mm is greater than 6, which may cause gcode checksum errors while printing depending on your firmeware, so a value of 6 will be used instead." << std::endl; - default_xyz_precision = 6; + std::cout << "warning: The provided default_xyz_precision " << args.default_xyz_precision << "mm is greater than 6, which may cause gcode checksum errors while printing depending on your firmeware, so a value of 6 will be used instead." << std::endl; + args.default_xyz_precision = 6; } - if (default_e_precision > 6) + if (args.default_e_precision > 6) { // warning - std::cout << "warning: The provided default_e_precision " << default_e_precision << "mm is greater than 6, which may cause gcode checksum errors while printing depending on your firmeware, so value of 6 will be used instead." << std::endl; - default_e_precision = 6; + std::cout << "warning: The provided default_e_precision " << args.default_e_precision << "mm is greater than 6, which may cause gcode checksum errors while printing depending on your firmeware, so value of 6 will be used instead." << std::endl; + args.default_e_precision = 6; } - if (extrusion_rate_variance_percent < 0) + if (args.extrusion_rate_variance_percent < 0) { // warning - std::cout << "warning: The provided extrusion_rate_variance_percent " << extrusion_rate_variance_percent << " is less than 0. Setting to the default." << std::endl; - extrusion_rate_variance_percent = DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT; + std::cout << "warning: The provided extrusion_rate_variance_percent " << args.extrusion_rate_variance_percent << " is less than 0. Setting to the default." << std::endl; + args.extrusion_rate_variance_percent = DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT; + } + + if (args.max_gcode_length < 0) + { + // warning + std::cout << "warning: The provided max_gcode_length " << args.max_gcode_length << " is less than 0. Setting to the default." << std::endl; + args.max_gcode_length = DEFAULT_MAX_GCODE_LENGTH; } if (has_error) @@ -331,95 +346,56 @@ int main(int argc, char* argv[]) // Ensure the log level name is valid std::vector log_names; - log_names.push_back("arc_welder.gcode_conversion"); + log_names.push_back(ARC_WELDER_LOGGER_NAME); std::vector log_levels; log_levels.push_back(log_levels::DEBUG); logger* p_logger = new logger(log_names, log_levels); p_logger->set_log_level_by_value(log_level_value); - - std::stringstream log_messages; - std::string temp_file_path = ""; - log_messages << std::fixed << std::setprecision(DEFAULT_ARG_DOUBLE_PRECISION); - if (source_file_path == target_file_path) + args.log = p_logger; + + arc_welder* p_arc_welder = NULL; + + if (progress_type == PROGRESS_TYPE_NONE) { - overwrite_source_file = true; - if (!utilities::get_temp_file_path_for_file(source_file_path, temp_file_path)) - { - log_messages << "The source and target path are the same, but a temporary file path could not be created. Is the path empty?"; - p_logger->log(0, INFO, log_messages.str()); - log_messages.clear(); - log_messages.str(""); - } - - // create a uuid with a tmp extension for the temporary file - log_messages << "Source and target path are the same. The source file will be overwritten. Temporary file path: " << temp_file_path; - p_logger->log(0, INFO, log_messages.str()); - log_messages.clear(); - log_messages.str(""); - target_file_path = temp_file_path; + p_logger->log(0, INFO, "Suppressing progress messages."); + args.callback = on_progress_suppress; } - log_messages << "Processing Gcode\n"; - log_messages << "\tSource File Path : " << source_file_path << "\n"; - if (overwrite_source_file) + else if (progress_type == PROGRESS_TYPE_FULL) { - log_messages << "\tTarget File Path (overwrite) : " << target_file_path << "\n"; - log_messages << "\tTemporary File Path : " << temp_file_path << "\n"; + p_logger->log(0, INFO, "Displaying full progress messages."); + args.callback = on_progress_full; } - else - { - log_messages << "\tTarget File File : " << target_file_path << "\n"; + else { + args.callback = on_progress_simple; } - - log_messages << "\tResolution : " << resolution_mm << "mm (+-" << std::setprecision(5) << resolution_mm/2.0 << "mm)\n"; - log_messages << "\tPath Tolerance : " << std::setprecision(3) << path_tolerance_percent*100.0 << "%\n"; - log_messages << "\tMaximum Arc Radius : " << std::setprecision(0) << max_radius_mm << "mm\n"; - log_messages << "\tMin Arc Segments : " << std::setprecision(0) << min_arc_segments << "\n"; - log_messages << "\tMM Per Arc Segment : " << std::setprecision(3) << mm_per_arc_segment << "\n"; - log_messages << "\tAllow 3D Arcs : " << (allow_3d_arcs ? "True" : "False") << "\n"; - log_messages << "\tAllow Travel Arcs : " << (allow_travel_arcs ? "True" : "False") << "\n"; - log_messages << "\tAllow Dynamic Precision : " << (allow_dynamic_precision ? "True" : "False") << "\n"; - log_messages << "\tDefault XYZ Precision : " << std::setprecision(0) << static_cast(default_xyz_precision) << "\n"; - log_messages << "\tDefault E Precision : " << std::setprecision(0) << static_cast(default_e_precision) << "\n"; - log_messages << "\tExtrusion Rate Variance % : " << std::setprecision(3) << extrusion_rate_variance_percent*100.0 << "%\n"; - log_messages << "\tG90/G91 Influences Extruder : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; - log_messages << "\tLog Level : " << log_level_string << "\n"; - log_messages << "\tHide Progress Updates : " << (hide_progress ? "True" : "False"); + // Log the arguments + std::stringstream log_messages; + log_messages << "Processing GCode."; + p_logger->log(0, INFO, log_messages.str()); + log_messages.clear(); + log_messages.str(""); + log_messages << args.str(); p_logger->log(0, INFO, log_messages.str()); - arc_welder* p_arc_welder = NULL; - - if (overwrite_source_file) - { - target_file_path = temp_file_path; - } - if (!hide_progress) - p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, path_tolerance_percent, max_radius_mm, min_arc_segments, mm_per_arc_segment, g90_g91_influences_extruder, allow_3d_arcs, allow_travel_arcs, allow_dynamic_precision, default_xyz_precision, default_e_precision, extrusion_rate_variance_percent, DEFAULT_GCODE_BUFFER_SIZE, on_progress); - else - p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, path_tolerance_percent, max_radius_mm, min_arc_segments, mm_per_arc_segment, g90_g91_influences_extruder, allow_3d_arcs, allow_travel_arcs, allow_dynamic_precision, default_xyz_precision, default_e_precision, extrusion_rate_variance_percent, DEFAULT_GCODE_BUFFER_SIZE, suppress_progress); + p_arc_welder = new arc_welder(args); + arc_welder_results results = p_arc_welder->process(); if (results.success) { - log_messages.clear(); - log_messages.str(""); - log_messages << "Target file at '" << target_file_path << "' created."; - - if (overwrite_source_file) + if (args.allow_travel_arcs) { log_messages.clear(); log_messages.str(""); - log_messages << "Deleting the original source file at '" << source_file_path << "'."; + log_messages << "Target File Travel Statistics:" << std::endl << results.progress.travel_statistics.str(); p_logger->log(0, INFO, log_messages.str()); - log_messages.clear(); - log_messages.str(""); - std::remove(source_file_path.c_str()); - log_messages << "Renaming temporary file at '" << target_file_path << "' to '" << source_file_path <<"'."; - p_logger->log(0, INFO, log_messages.str()); - std::rename(target_file_path.c_str(), source_file_path.c_str()); } + log_messages.clear(); log_messages.str(""); - log_messages << std::endl << results.progress.segment_statistics.str(); + log_messages << "Target File Extrusion Statistics:" << std::endl << results.progress.segment_statistics.str(); p_logger->log(0, INFO, log_messages.str() ); + + log_messages.clear(); log_messages.str(""); @@ -438,13 +414,21 @@ int main(int argc, char* argv[]) return 0; } -bool on_progress(arc_welder_progress progress, logger* p_logger, int logger_type) +bool on_progress_full(arc_welder_progress progress, logger* p_logger, int logger_type) { std::cout << "Progress: "<< progress.str() << std::endl; std::cout.flush(); return true; } -bool suppress_progress(arc_welder_progress progress, logger* p_logger, int logger_type) + +bool on_progress_simple(arc_welder_progress progress, logger* p_logger, int logger_type) +{ + std::cout << "Progress: " << progress.simple_progress_str() << std::endl; + std::cout.flush(); + return true; +} + +bool on_progress_suppress(arc_welder_progress progress, logger* p_logger, int logger_type) { return true; } diff --git a/ArcWelderConsole/ArcWelderConsole.h b/ArcWelderConsole/ArcWelderConsole.h index 64425c9..1e4762f 100644 --- a/ArcWelderConsole/ArcWelderConsole.h +++ b/ArcWelderConsole/ArcWelderConsole.h @@ -25,6 +25,8 @@ #pragma once #include "arc_welder.h" #include "version.h" -static bool on_progress(arc_welder_progress progress, logger* p_logger, int logger_type); -static bool suppress_progress(arc_welder_progress progress, logger* p_logger, int logger_type); +static bool on_progress_full(arc_welder_progress progress, logger* p_logger, int logger_type); +static bool on_progress_simple(arc_welder_progress progress, logger* p_logger, int logger_type); +static bool on_progress_suppress(arc_welder_progress progress, logger* p_logger, int logger_type); + diff --git a/ArcWelderTest/ArcWelderTest.cpp b/ArcWelderTest/ArcWelderTest.cpp index 95aebc5..2ac30b1 100644 --- a/ArcWelderTest/ArcWelderTest.cpp +++ b/ArcWelderTest/ArcWelderTest.cpp @@ -266,17 +266,6 @@ static gcode_position_args get_5_extruder_position_args() static void TestAntiStutter(std::string filePath) { - //double max_resolution = DEFAULT_RESOLUTION_MM; - double max_resolution = 0.05; - double max_radius_mm = 100000; - //double max_radius_mm = 10000; - //int min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; - int min_arc_segments = 0; - double mm_per_arc_segment = 0; - - //double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT; // 1 percent - double path_tolerance_percent = 0.05; - //double path_tolerance_percent = 0.05; std::vector logger_names; logger_names.push_back("arc_welder.gcode_conversion"); std::vector logger_levels; @@ -289,29 +278,7 @@ static void TestAntiStutter(std::string filePath) logger_levels.push_back(log_levels::CRITICAL); logger* p_logger = new logger(logger_names, logger_levels); p_logger->set_log_level(INFO); - //p_logger->set_log_level(DEBUG); - //p_logger->set_log_level_by_value(5); - //arc_welder arc_welder_obj(BENCHY_0_5_MM_NO_WIPE, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, false, 50, static_cast(on_progress)); - //arc_welder arc_welder_obj(SIX_SPEED_TEST, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, false, 50, on_progress); - arc_welder arc_welder_obj( - BENCHY_DIFFICULT, - "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", - p_logger, - max_resolution, - path_tolerance_percent, - DEFAULT_MAX_RADIUS_MM, - min_arc_segments, - mm_per_arc_segment, - true, - true, - true, //DEFAULT_ALLOW_TRAVEL_ARCS, - DEFAULT_ALLOW_DYNAMIC_PRECISION, - DEFAULT_XYZ_PRECISION, - DEFAULT_E_PRECISION, - //DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT, - 1000000, - DEFAULT_GCODE_BUFFER_SIZE, - on_progress); + //FIRMWARE_COMPENSATION_TEST_1 //BENCHY_MIN_RADIUS_TEST //BENCHY_DIFFICULT @@ -335,6 +302,17 @@ static void TestAntiStutter(std::string filePath) // BENCHY_L1_DIFFICULT // SPIRAL_TEST // SPIRAL_VASE_TEST_FUNNEL + std::string source_path = TravelWipeTest; + std::string target_path = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode"; + arc_welder_args args(source_path, target_path, p_logger); + args.callback = on_progress; + // override any arguments here; + args.allow_travel_arcs = true; + args.allow_3d_arcs = true; + args.max_radius_mm = 9999; + args.resolution_mm = 0.05; + arc_welder arc_welder_obj(args); + arc_welder_results results = arc_welder_obj.process(); p_logger->log(0, INFO, results.progress.detail_str()); p_logger->log(0, INFO, "Processing Complete."); diff --git a/ArcWelderTest/ArcWelderTest.h b/ArcWelderTest/ArcWelderTest.h index b4331e9..e854c4b 100644 --- a/ArcWelderTest/ArcWelderTest.h +++ b/ArcWelderTest/ArcWelderTest.h @@ -83,7 +83,7 @@ static std::string ISSUE_PRICKLYPEAR_LAYER_0_114 = "C:\\Users\\Brad\\Documents\\ static std::string COLINEAR_TEST_1 = "C:\\Users\\Brad\\Documents\\AntiStutter\\Sanity Checks\\G2_colinear_test.gcode"; static std::string SPIRAL_TEST = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\smoothietest\\SPIRAL_TEST.gcode"; static std::string SPIRAL_TRAVEL_TEST = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\smoothietest\\SPIRAL_TRAVEL_TEST.gcode"; - +static std::string TravelWipeTest = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\smoothietest\\TravelWipeTest.gcode"; static std::string SPIRAL_TEST_PRECISION = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\smoothietest\\SPIRAL_TEST_precision.gcode"; static std::string SPIRAL_VASE_TEST_DOUBLE_SPIRAL = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\SpiralVaseTest\\SpiralVaseTest_DOUBLE_SPIRAL.gcode"; static std::string SPIRAL_VASE_TEST_CYLINDER = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\SpiralVaseTest\\SpiralVaseTest_Cylinder.gcode"; diff --git a/GcodeProcessorLib/logger.cpp b/GcodeProcessorLib/logger.cpp index 5b1e4eb..3bde18e 100644 --- a/GcodeProcessorLib/logger.cpp +++ b/GcodeProcessorLib/logger.cpp @@ -57,10 +57,24 @@ void logger::set_log_level_by_value(const int level_value) logger_levels_[type_index] = log_level; } } + void logger::set_log_level(const int logger_type, const int log_level) { logger_levels_[logger_type] = log_level; } +std::string logger::get_log_level_name(std::string logger_name) +{ + std::string log_level_name = "UNKNOWN"; + for (int type_index = 0; type_index < num_loggers_; type_index++) + { + if (logger_names_[type_index] == logger_name) + { + log_level_name = log_level_names[logger_levels_[type_index]]; + break; + } + } + return log_level_name; +} void logger::set_log_level(const int log_level) { diff --git a/GcodeProcessorLib/logger.h b/GcodeProcessorLib/logger.h index 9db2df1..f345097 100644 --- a/GcodeProcessorLib/logger.h +++ b/GcodeProcessorLib/logger.h @@ -36,7 +36,7 @@ enum log_levels { NOSET, VERBOSE, DEBUG, INFO, WARNING , ERROR, CRITICAL}; static const int log_level_names_size = 7; static const char* log_level_names[] = {"NOSET", "VERBOSE", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}; const static int log_level_values[LOG_LEVEL_COUNT] = { 0, 5, 10, 20, 30, 40, 50}; - +#define DEFAULT_LOG_LEVEL_VALUE 40 class logger { public: @@ -48,7 +48,8 @@ public: void set_log_level(const int logger_type, const int log_level); void set_log_level(const int log_level); - + + std::string get_log_level_name(std::string logger_name); virtual void log(const int logger_type, const int log_level, const std::string& message); virtual void log(const int logger_type, const int log_level, const std::string& message, bool is_exception); virtual void log_exception(const int logger_type, const std::string& message); diff --git a/GcodeProcessorLib/utilities.cpp b/GcodeProcessorLib/utilities.cpp index a723cdf..4db0f6a 100644 --- a/GcodeProcessorLib/utilities.cpp +++ b/GcodeProcessorLib/utilities.cpp @@ -217,7 +217,7 @@ int utilities::get_num_digits(int x) (x < 10000000 ? 7 : (x < 100000000 ? 8 : (x < 1000000000 ? 9 : - 10))))))))); + (x < 10000000000 ? 10 : -1)))))))))); } int utilities::get_num_digits(double x) diff --git a/GcodeProcessorLib/utilities.h b/GcodeProcessorLib/utilities.h index acbea6c..3261f91 100644 --- a/GcodeProcessorLib/utilities.h +++ b/GcodeProcessorLib/utilities.h @@ -55,7 +55,6 @@ public: static double get_percent_change(int v1, int v2); static double get_percent_change(double v1, double v2); static std::string get_percent_change_string(int v1, int v2, int precision); - static int get_num_digits(int x); static int get_num_digits(double x); diff --git a/PyArcWelder/py_arc_welder.cpp b/PyArcWelder/py_arc_welder.cpp index 7fdf9bd..482c09b 100644 --- a/PyArcWelder/py_arc_welder.cpp +++ b/PyArcWelder/py_arc_welder.cpp @@ -24,105 +24,420 @@ PyObject* py_arc_welder::build_py_progress(const arc_welder_progress& progress, std::string guid) { - std::string segment_statistics = progress.segment_statistics.str(); - PyObject* pyGuid = gcode_arc_converter::PyUnicode_SafeFromString(guid); - if (pyGuid == NULL) - return NULL; - PyObject* pyMessage = gcode_arc_converter::PyUnicode_SafeFromString(segment_statistics); - if (pyMessage == NULL) - return NULL; - double total_count_reduction_percent = progress.segment_statistics.get_total_count_reduction_percent(); - PyObject* py_progress = Py_BuildValue("{s:d,s:d,s:d,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:f,s:f,s:f,s:f,s:i,s:i,s:f}", - "percent_complete", - progress.percent_complete, //1 - "seconds_elapsed", - progress.seconds_elapsed, //2 - "seconds_remaining", - progress.seconds_remaining, //3 - "gcodes_processed", - progress.gcodes_processed, //4 - "lines_processed", - progress.lines_processed, //5 - "points_compressed", - progress.points_compressed, //6 - "arcs_created", - progress.arcs_created, //7 - "arcs_aborted_by_flowrate", - progress.arcs_aborted_by_flow_rate, //8 - "num_firmware_compensations", - progress.num_firmware_compensations, //9 - "source_file_position", - progress.source_file_position, //10 - "source_file_size", - progress.source_file_size, //11 - "target_file_size", - progress.target_file_size, //12 - "compression_ratio", - progress.compression_ratio, //13 - "compression_percent", - progress.compression_percent, //14 - "source_file_total_length", - progress.segment_statistics.total_length_source, //15 - "target_file_total_length", - progress.segment_statistics.total_length_target, //16 - "source_file_total_count", - progress.segment_statistics.total_count_source, //17 - "target_file_total_count", - progress.segment_statistics.total_count_target, //18 - "total_count_reduction_percent", - total_count_reduction_percent //19 - - ); + PyObject* pyGuid = gcode_arc_converter::PyUnicode_SafeFromString(guid); + if (pyGuid == NULL) + return NULL; + // Extrusion Statistics + std::string segment_statistics = progress.segment_statistics.str(); + PyObject* pyMessage = gcode_arc_converter::PyUnicode_SafeFromString(segment_statistics); + if (pyMessage == NULL) + return NULL; + double total_count_reduction_percent = progress.segment_statistics.get_total_count_reduction_percent(); + // Travel Statistics + std::string segment_travel_statistics = progress.travel_statistics.str(); + PyObject* pyTravelMessage = gcode_arc_converter::PyUnicode_SafeFromString(segment_travel_statistics); + if (pyMessage == NULL) + return NULL; + double total_travel_count_reduction_percent = progress.travel_statistics.get_total_count_reduction_percent(); + PyObject* py_progress = Py_BuildValue("{s:d,s:d,s:d,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:f,s:f,s:f,s:f,s:i,s:i,s:f,s:f,s:f,s:i,s:i,s:f}", + "percent_complete", + progress.percent_complete, //1 + "seconds_elapsed", + progress.seconds_elapsed, //2 + "seconds_remaining", + progress.seconds_remaining, //3 + "gcodes_processed", + progress.gcodes_processed, //4 + "lines_processed", + progress.lines_processed, //5 + "points_compressed", + progress.points_compressed, //6 + "arcs_created", + progress.arcs_created, //7 + "arcs_aborted_by_flowrate", + progress.arcs_aborted_by_flow_rate, //8 + "num_firmware_compensations", + progress.num_firmware_compensations, //9 + "num_gcode_length_exceptions", + progress.num_gcode_length_exceptions, //10 + "source_file_position", + progress.source_file_position, //11 + "source_file_size", + progress.source_file_size, //12 + "target_file_size", + progress.target_file_size, //13 + "compression_ratio", + progress.compression_ratio, //14 + "compression_percent", + progress.compression_percent, //15 + "source_file_total_length", + progress.segment_statistics.total_length_source, //16 + "target_file_total_length", + progress.segment_statistics.total_length_target, //17 + "source_file_total_count", + progress.segment_statistics.total_count_source, //18 + "target_file_total_count", + progress.segment_statistics.total_count_target, //19 + "total_count_reduction_percent", + total_count_reduction_percent, //20 + "source_file_total_travel_length", + progress.travel_statistics.total_length_source, //21 + "target_file_total_travel_length", + progress.travel_statistics.total_length_target, //22 + "source_file_total_travel_count", + progress.travel_statistics.total_count_source, //23 + "target_file_total_travel_count", + progress.travel_statistics.total_count_target, //24 + "total_travel_count_reduction_percent", + total_travel_count_reduction_percent //25 - if (py_progress == NULL) - { - return NULL; - } - // Due to a CRAZY issue, I have to add this item after building the py_progress object, - // else it crashes in python 2.7. Looking forward to retiring this backwards - // compatible code... - PyDict_SetItemString(py_progress, "segment_statistics_text", pyMessage); - PyDict_SetItemString(py_progress, "guid", pyGuid); - return py_progress; + ); + + if (py_progress == NULL) + { + return NULL; + } + // Due to a CRAZY issue, I have to add this item after building the py_progress object, + // else it crashes in python 2.7. Looking forward to retiring this backwards + // compatible code... + PyDict_SetItemString(py_progress, "segment_statistics_text", pyMessage); + PyDict_SetItemString(py_progress, "segment_travel_statistics_text", pyTravelMessage); + PyDict_SetItemString(py_progress, "guid", pyGuid); + return py_progress; } bool py_arc_welder::on_progress_(const arc_welder_progress& progress) { - PyObject* py_dict = py_arc_welder::build_py_progress(progress, guid_); - if (py_dict == NULL) - { - return false; - } - PyObject* func_args = Py_BuildValue("(O)", py_dict); - if (func_args == NULL) - { - Py_DECREF(py_dict); - return false; // This was returning true, I think it was a typo. Making a note just in case. - } - - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* pContinueProcessing = PyObject_CallObject(py_progress_callback_, func_args); - PyGILState_Release(gstate); - Py_DECREF(func_args); - Py_DECREF(py_dict); - bool continue_processing; - if (pContinueProcessing == NULL) - { - // no return value was supply, assume true, but without decrefing pContinueProcessing - continue_processing = true; - } - else - { - if (pContinueProcessing == Py_None) - { - continue_processing = true; - } - else - { - continue_processing = PyLong_AsLong(pContinueProcessing) > 0; - } - Py_DECREF(pContinueProcessing); - } - - return continue_processing; + PyObject* py_dict = py_arc_welder::build_py_progress(progress, guid_); + if (py_dict == NULL) + { + return false; + } + PyObject* func_args = Py_BuildValue("(O)", py_dict); + if (func_args == NULL) + { + Py_DECREF(py_dict); + return false; // This was returning true, I think it was a typo. Making a note just in case. + } + + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject* pContinueProcessing = PyObject_CallObject(py_progress_callback_, func_args); + PyGILState_Release(gstate); + Py_DECREF(func_args); + Py_DECREF(py_dict); + bool continue_processing; + if (pContinueProcessing == NULL) + { + // no return value was supply, assume true, but without decrefing pContinueProcessing + continue_processing = true; + } + else + { + if (pContinueProcessing == Py_None) + { + continue_processing = true; + } + else + { + continue_processing = PyLong_AsLong(pContinueProcessing) > 0; + } + Py_DECREF(pContinueProcessing); + } + + return continue_processing; } + +bool py_gcode_arc_args::parse_args(PyObject* py_args, py_logger* p_py_logger, py_gcode_arc_args& args, PyObject** py_progress_callback) +{ + p_py_logger->log( + GCODE_CONVERSION, INFO, + "Parsing GCode Conversion Args." + ); + +#pragma region Required_Arguments +#pragma region guid + // Extract the job guid + PyObject* py_guid = PyDict_GetItemString(py_args, "guid"); + if (py_guid == NULL) + { + std::string message = "ParseArgs - Unable to retrieve required parameter 'guid' from the args."; + p_py_logger->log_exception(GCODE_CONVERSION, message); + return false; + } + args.guid = gcode_arc_converter::PyUnicode_SafeAsString(py_guid); +#pragma endregion guid +#pragma region source_path + // Extract the source file path + PyObject* py_source_path = PyDict_GetItemString(py_args, "source_path"); + if (py_source_path == NULL) + { + std::string message = "ParseArgs -Unable to retrieve required parameter 'source_path' from the args."; + p_py_logger->log_exception(GCODE_CONVERSION, message); + return false; + } + args.source_path = gcode_arc_converter::PyUnicode_SafeAsString(py_source_path); +#pragma endregion source_path +#pragma region target_path + // Extract the target file path + PyObject* py_target_path = PyDict_GetItemString(py_args, "target_path"); + if (py_target_path == NULL) + { + std::string message = "ParseArgs - Unable to retrieve required parameter 'target_path' from the args."; + p_py_logger->log_exception(GCODE_CONVERSION, message); + return false; + } + args.target_path = gcode_arc_converter::PyUnicode_SafeAsString(py_target_path); +#pragma endregion target_path +#pragma region on_progress_received + // on_progress_received + PyObject* py_on_progress_received = PyDict_GetItemString(py_args, "on_progress_received"); + if (py_on_progress_received == NULL) + { + std::string message = "ParseArgs - Unable to retrieve required parameter 'on_progress_received' from the args."; + p_py_logger->log_exception(GCODE_CONVERSION, message); + return false; + } + // need to incref this so it doesn't vanish later (borrowed reference we are saving) + Py_XINCREF(py_on_progress_received); + *py_progress_callback = py_on_progress_received; +#pragma endregion on_progress_received +#pragma endregion Required_Arguments + +#pragma region Optional_Arguments +#pragma region resolution_mm + // Extract the resolution in millimeters + PyObject* py_resolution_mm = PyDict_GetItemString(py_args, "resolution_mm"); + if (py_resolution_mm == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'resolution_mm' parameter from the args."; + p_py_logger->log(GCODE_CONVERSION, WARNING, message); + } + else { + args.resolution_mm = gcode_arc_converter::PyFloatOrInt_AsDouble(py_resolution_mm); + if (args.resolution_mm <= 0) + { + args.resolution_mm = 0.05; // Set to the default if no resolution is provided, or if it is less than 0. + } + } +#pragma endregion resolution_mm +#pragma region allow_dynamic_precision + // extract allow_dynamic_precision + PyObject* py_allow_dynamic_precision = PyDict_GetItemString(py_args, "allow_dynamic_precision"); + if (py_allow_dynamic_precision == NULL) + { + std::string message = "ParseArgs - Unable to retrieve 'allow_dynamic_precision' from the args."; + p_py_logger->log(GCODE_CONVERSION, WARNING, message); + } + else { + args.allow_dynamic_precision = PyLong_AsLong(py_allow_dynamic_precision) > 0; + } +#pragma endregion allow_dynamic_precision +#pragma region default_xyz_precision + // extract default_xyz_precision + PyObject* py_default_xyz_precision = PyDict_GetItemString(py_args, "default_xyz_precision"); + if (py_default_xyz_precision == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'default_xyz_precision' parameter from the args."; + p_py_logger->log(GCODE_CONVERSION, WARNING, message); + } + else { + args.default_xyz_precision = gcode_arc_converter::PyFloatOrInt_AsDouble(py_default_xyz_precision); + if (args.default_xyz_precision < 3) + { + std::string message = "ParseArgs - The default XYZ precision received was less than 3, which could cause problems printing arcs. Setting to 3."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + args.default_xyz_precision = 3; + } + else if (args.default_xyz_precision > 6) + { + std::string message = "ParseArgs - The default XYZ precision received was greater than 6, which could can cause checksum errors depending on your firmware. Setting to 6."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + args.default_xyz_precision = 6; + } + } +#pragma endregion default_xyz_precision +#pragma region default_e_precision + // extract default_e_precision + PyObject* py_default_e_precision = PyDict_GetItemString(py_args, "default_e_precision"); + if (py_default_e_precision == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'default_e_precision parameter' from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else { + args.default_e_precision = gcode_arc_converter::PyFloatOrInt_AsDouble(py_default_e_precision); + if (args.default_e_precision < 3) + { + std::string message = "ParseArgs - The default E precision received was less than 3, which could cause extrusion problems. Setting to 3."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + args.default_e_precision = 3; + } + else if (args.default_e_precision > 6) + { + std::string message = "ParseArgs - The default E precision received was greater than 6, which could can cause checksum errors depending on your firmware. Setting to 6."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + args.default_e_precision = 6; + } + } +#pragma endregion default_e_precision +#pragma region extrusion_rate_variance_percent + // Extract the extrusion_rate_variance + PyObject* py_extrusion_rate_variance_percent = PyDict_GetItemString(py_args, "extrusion_rate_variance_percent"); + if (py_extrusion_rate_variance_percent == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'extrusion_rate_variance_percent' parameter from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.extrusion_rate_variance_percent = gcode_arc_converter::PyFloatOrInt_AsDouble(py_extrusion_rate_variance_percent); + if (args.extrusion_rate_variance_percent < 0) + { + args.extrusion_rate_variance_percent = DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT; // Set to the default if no resolution is provided, or if it is less than 0. + } + } +#pragma endregion extrusion_rate_variance_percent +#pragma region path_tolerance_percent + // Extract the path tolerance_percent + PyObject* py_path_tolerance_percent = PyDict_GetItemString(py_args, "path_tolerance_percent"); + if (py_path_tolerance_percent == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'path_tolerance_percent' parameter from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.path_tolerance_percent = gcode_arc_converter::PyFloatOrInt_AsDouble(py_path_tolerance_percent); + if (args.path_tolerance_percent < 0) + { + args.path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT; // Set to the default if no resolution is provided, or if it is less than 0. + } + } +#pragma endregion path_tolerance_percent +#pragma region max_radius_mm + // Extract the max_radius in mm + PyObject* py_max_radius_mm = PyDict_GetItemString(py_args, "max_radius_mm"); + if (py_max_radius_mm == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'max_radius_mm' parameter from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.max_radius_mm = gcode_arc_converter::PyFloatOrInt_AsDouble(py_max_radius_mm); + if (args.max_radius_mm > DEFAULT_MAX_RADIUS_MM) + { + args.max_radius_mm = DEFAULT_MAX_RADIUS_MM; // Set to the default if no resolution is provided, or if it is less than 0. + } + } +#pragma endregion max_radius_mm +#pragma region mm_per_arc_segment + // Extract the mm_per_arc_segment + PyObject* py_mm_per_arc_segment = PyDict_GetItemString(py_args, "mm_per_arc_segment"); + if (py_mm_per_arc_segment == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'mm_per_arc_segment' parameter from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.mm_per_arc_segment = gcode_arc_converter::PyFloatOrInt_AsDouble(py_mm_per_arc_segment); + if (args.mm_per_arc_segment < 0) + { + args.mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; + } + } +#pragma endregion mm_per_arc_segment +#pragma region min_arc_segments + // Extract min_arc_segments + PyObject* py_min_arc_segments = PyDict_GetItemString(py_args, "min_arc_segments"); + if (py_min_arc_segments == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'min_arc_segments' parameter from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.min_arc_segments = (int)gcode_arc_converter::PyIntOrLong_AsLong(py_min_arc_segments); + if (args.min_arc_segments < 0) + { + args.min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; // Set to the default if no resolution is provided, or if it is less than 0. + } + } +#pragma endregion min_arc_segments +#pragma region max_gcode_length + // Extract max_gcode_length + PyObject* py_max_gcode_length = PyDict_GetItemString(py_args, "max_gcode_length"); + if (py_max_gcode_length == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the 'max_gcode_length' parameter from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.max_gcode_length = (int)gcode_arc_converter::PyIntOrLong_AsLong(py_max_gcode_length); + if (args.max_gcode_length < 0) + { + args.max_gcode_length = DEFAULT_MAX_GCODE_LENGTH; + } + } +#pragma endregion max_gcode_length +#pragma region allow_3d_arcs + // extract allow_3d_arcs + PyObject* py_allow_3d_arcs = PyDict_GetItemString(py_args, "allow_3d_arcs"); + if (py_allow_3d_arcs == NULL) + { + std::string message = "ParseArgs - Unable to retrieve 'allow_3d_arcs' from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.allow_3d_arcs = PyLong_AsLong(py_allow_3d_arcs) > 0; + } +#pragma endregion allow_3d_arcs +#pragma region allow_travel_arcs + // extract allow_travel_arcs + PyObject* py_allow_travel_arcs = PyDict_GetItemString(py_args, "allow_travel_arcs"); + if (py_allow_travel_arcs == NULL) + { + std::string message = "ParseArgs - Unable to retrieve 'allow_travel_arcs' from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.allow_travel_arcs = PyLong_AsLong(py_allow_travel_arcs) > 0; + } +#pragma endregion allow_travel_arcs +#pragma region g90_g91_influences_extruder + // Extract G90/G91 influences extruder + // g90_influences_extruder + PyObject* py_g90_g91_influences_extruder = PyDict_GetItemString(py_args, "g90_g91_influences_extruder"); + if (py_g90_g91_influences_extruder == NULL) + { + std::string message = "ParseArgs - Unable to retrieve 'g90_g91_influences_extruder' from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + args.g90_g91_influences_extruder = PyLong_AsLong(py_g90_g91_influences_extruder) > 0; + } +#pragma endregion g90_g91_influences_extruder +#pragma region log_level + // Extract log_level + PyObject* py_log_level = PyDict_GetItemString(py_args, "log_level"); + if (py_log_level == NULL) + { + std::string message = "ParseArgs - Unable to retrieve 'log_level' from the args."; + p_py_logger->log(WARNING, GCODE_CONVERSION, message); + } + else + { + int log_level_value = static_cast(PyLong_AsLong(py_log_level)); + // determine the log level as an index rather than as a value + args.log_level = p_py_logger->get_log_level_for_value(log_level_value); + } +#pragma endregion log_level +#pragma endregion Optional_Arguments + + return true; +} \ No newline at end of file diff --git a/PyArcWelder/py_arc_welder.h b/PyArcWelder/py_arc_welder.h index 40a9cab..686a9cd 100644 --- a/PyArcWelder/py_arc_welder.h +++ b/PyArcWelder/py_arc_welder.h @@ -31,49 +31,32 @@ #else #include #endif + +struct py_gcode_arc_args : arc_welder_args { + py_gcode_arc_args() : arc_welder_args() { + log_level = INFO; + py_progress_callback = NULL; + guid = ""; + + }; + py_gcode_arc_args(std::string source_path, std::string target_path, logger* log, std::string progress_guid, PyObject* progress_callback) : arc_welder_args(source_path, target_path, log) { + guid = progress_guid; + py_progress_callback = progress_callback; + }; + + static bool parse_args(PyObject* py_args, py_logger* p_py_logger, py_gcode_arc_args& args, PyObject** py_progress_callback); + int log_level; + std::string guid; + PyObject* py_progress_callback; +}; + class py_arc_welder : public arc_welder { public: - py_arc_welder( - std::string guid, - std::string source_path, - std::string target_path, - py_logger* logger, - double resolution_mm, - double path_tolerance_percent, - double max_radius, - 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, - PyObject* py_progress_callback - ): arc_welder( - source_path, - target_path, - logger, - resolution_mm, - path_tolerance_percent, - max_radius, - min_arc_segments, - mm_per_arc_segment, - g90_g91_influences_extruder, - allow_3d_arcs, - allow_travel_arcs, - allow_dynamic_precision, - default_xyz_precision, - default_e_precision, - extrusion_rate_variance_percent, - buffer_size, - NULL - ){ - guid_ = guid; - py_progress_callback_ = py_progress_callback; + py_arc_welder(py_gcode_arc_args args): arc_welder( (arc_welder_args)args) + { + guid_ = args.guid; + py_progress_callback_ = args.py_progress_callback; } virtual ~py_arc_welder() { diff --git a/PyArcWelder/py_arc_welder_extension.cpp b/PyArcWelder/py_arc_welder_extension.cpp index 19a2274..b386d9f 100644 --- a/PyArcWelder/py_arc_welder_extension.cpp +++ b/PyArcWelder/py_arc_welder_extension.cpp @@ -186,7 +186,7 @@ extern "C" py_gcode_arc_args args; PyObject* py_progress_callback = NULL; - if (!ParseArgs(py_convert_file_args, args, &py_progress_callback)) + if (!py_gcode_arc_args::parse_args(py_convert_file_args, p_py_logger, args, &py_progress_callback)) { return NULL; } @@ -195,26 +195,9 @@ extern "C" std::string message = "py_gcode_arc_converter.ConvertFile - Beginning Arc Conversion."; p_py_logger->log(GCODE_CONVERSION, INFO, message); - py_arc_welder arc_welder_obj( - args.guid, - args.source_path, - args.target_path, - p_py_logger, - 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, - DEFAULT_GCODE_BUFFER_SIZE, - py_progress_callback - ); + args.py_progress_callback = py_progress_callback; + args.log = p_py_logger; + py_arc_welder arc_welder_obj(args); arc_welder_results results = arc_welder_obj.process(); message = "py_gcode_arc_converter.ConvertFile - Arc Conversion Complete."; p_py_logger->log(GCODE_CONVERSION, INFO, message); @@ -239,237 +222,5 @@ extern "C" } } -static bool ParseArgs(PyObject* py_args, py_gcode_arc_args& args, PyObject** py_progress_callback) -{ - p_py_logger->log( - GCODE_CONVERSION, INFO, - "Parsing GCode Conversion Args." - ); - - // Extract the job guid - PyObject* py_guid = PyDict_GetItemString(py_args, "guid"); - if (py_guid == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the guid parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.guid = gcode_arc_converter::PyUnicode_SafeAsString(py_guid); - - // Extract the source file path - PyObject* py_source_path = PyDict_GetItemString(py_args, "source_path"); - if (py_source_path == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the source_path parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.source_path = gcode_arc_converter::PyUnicode_SafeAsString(py_source_path); - - // Extract the target file path - PyObject* py_target_path = PyDict_GetItemString(py_args, "target_path"); - if (py_target_path == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the target_path parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.target_path = gcode_arc_converter::PyUnicode_SafeAsString(py_target_path); - - // Extract the resolution in millimeters - PyObject* py_resolution_mm = PyDict_GetItemString(py_args, "resolution_mm"); - if (py_resolution_mm == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the resolution_mm parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.resolution_mm = gcode_arc_converter::PyFloatOrInt_AsDouble(py_resolution_mm); - if (args.resolution_mm <= 0) - { - args.resolution_mm = 0.05; // Set to the default if no resolution is provided, or if it is less than 0. - } - - // extract allow_dynamic_precision - PyObject* py_allow_dynamic_precision = PyDict_GetItemString(py_args, "allow_dynamic_precision"); - if (py_allow_dynamic_precision == NULL) - { - std::string message = "ParseArgs - Unable to retrieve allow_dynamic_precision from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.allow_dynamic_precision = PyLong_AsLong(py_allow_dynamic_precision) > 0; - - // extract default_xyz_precision - PyObject* py_default_xyz_precision = PyDict_GetItemString(py_args, "default_xyz_precision"); - if (py_default_xyz_precision == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the default_xyz_precision parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.default_xyz_precision = gcode_arc_converter::PyFloatOrInt_AsDouble(py_default_xyz_precision); - if (args.default_xyz_precision < 3) - { - std::string message = "ParseArgs - The default XYZ precision received was less than 3, which could cause problems printing arcs. Setting to 3."; - p_py_logger->log(WARNING, GCODE_CONVERSION, message); - args.default_xyz_precision = 3; - } - else if (args.default_xyz_precision > 6) - { - std::string message = "ParseArgs - The default XYZ precision received was greater than 6, which could can cause checksum errors depending on your firmware. Setting to 6."; - p_py_logger->log(WARNING, GCODE_CONVERSION, message); - args.default_xyz_precision = 6; - } - - // extract default_e_precision - PyObject* py_default_e_precision = PyDict_GetItemString(py_args, "default_e_precision"); - if (py_default_e_precision == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the default_e_precision parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.default_e_precision = gcode_arc_converter::PyFloatOrInt_AsDouble(py_default_e_precision); - if (args.default_e_precision < 3) - { - std::string message = "ParseArgs - The default E precision received was less than 3, which could cause extrusion problems. Setting to 3."; - p_py_logger->log(WARNING, GCODE_CONVERSION, message); - args.default_e_precision = 3; - } - else if (args.default_e_precision > 6) - { - std::string message = "ParseArgs - The default E precision received was greater than 6, which could can cause checksum errors depending on your firmware. Setting to 6."; - p_py_logger->log(WARNING, GCODE_CONVERSION, message); - args.default_e_precision = 6; - } - - // Extract the extrusion_rate_variance - PyObject* py_extrusion_rate_variance_percent = PyDict_GetItemString(py_args, "extrusion_rate_variance_percent"); - if (py_extrusion_rate_variance_percent == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the extrusion_rate_variance_percent parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.extrusion_rate_variance_percent = gcode_arc_converter::PyFloatOrInt_AsDouble(py_extrusion_rate_variance_percent); - if (args.extrusion_rate_variance_percent < 0) - { - args.extrusion_rate_variance_percent = DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT; // Set to the default if no resolution is provided, or if it is less than 0. - } - - // Extract the path tolerance_percent - PyObject* py_path_tolerance_percent = PyDict_GetItemString(py_args, "path_tolerance_percent"); - if (py_path_tolerance_percent == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the path_tolerance_percent parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.path_tolerance_percent = gcode_arc_converter::PyFloatOrInt_AsDouble(py_path_tolerance_percent); - if (args.path_tolerance_percent < 0) - { - args.path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT; // Set to the default if no resolution is provided, or if it is less than 0. - } - // Extract the max_radius in mm - PyObject* py_max_radius_mm = PyDict_GetItemString(py_args, "max_radius_mm"); - if (py_max_radius_mm == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the max_radius_mm parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.max_radius_mm = gcode_arc_converter::PyFloatOrInt_AsDouble(py_max_radius_mm); - if (args.max_radius_mm > DEFAULT_MAX_RADIUS_MM) - { - args.max_radius_mm = DEFAULT_MAX_RADIUS_MM; // Set to the default if no resolution is provided, or if it is less than 0. - } - - // Extract the mm_per_arc_segment - PyObject* py_mm_per_arc_segment = PyDict_GetItemString(py_args, "mm_per_arc_segment"); - if (py_mm_per_arc_segment == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the mm_per_arc_segment parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.mm_per_arc_segment = gcode_arc_converter::PyFloatOrInt_AsDouble(py_mm_per_arc_segment); - if (args.mm_per_arc_segment < 0) - { - args.mm_per_arc_segment = 0; - } - - // Extract min_arc_segments - PyObject* py_min_arc_segments = PyDict_GetItemString(py_args, "min_arc_segments"); - if (py_min_arc_segments == NULL) - { - std::string message = "ParseArgs - Unable to retrieve the min_arc_segments parameter from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.min_arc_segments = (int) gcode_arc_converter::PyIntOrLong_AsLong(py_min_arc_segments); - if (args.min_arc_segments < 0) - { - args.min_arc_segments = 0; // Set to the default if no resolution is provided, or if it is less than 0. - } - - // extract allow_3d_arcs - PyObject* py_allow_3d_arcs = PyDict_GetItemString(py_args, "allow_3d_arcs"); - if (py_allow_3d_arcs == NULL) - { - std::string message = "ParseArgs - Unable to retrieve allow_3d_arcs from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.allow_3d_arcs = PyLong_AsLong(py_allow_3d_arcs) > 0; - - // extract allow_travel_arcs - PyObject* py_allow_travel_arcs = PyDict_GetItemString(py_args, "allow_travel_arcs"); - if (py_allow_travel_arcs == NULL) - { - std::string message = "ParseArgs - Unable to retrieve allow_travel_arcs from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.allow_travel_arcs = PyLong_AsLong(py_allow_travel_arcs) > 0; - - // Extract G90/G91 influences extruder - // g90_influences_extruder - PyObject* py_g90_g91_influences_extruder = PyDict_GetItemString(py_args, "g90_g91_influences_extruder"); - if (py_g90_g91_influences_extruder == NULL) - { - std::string message = "ParseArgs - Unable to retrieve g90_g91_influences_extruder from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - args.g90_g91_influences_extruder = PyLong_AsLong(py_g90_g91_influences_extruder) > 0; - - // on_progress_received - PyObject* py_on_progress_received = PyDict_GetItemString(py_args, "on_progress_received"); - if (py_on_progress_received == NULL) - { - std::string message = "ParseArgs - Unable to retrieve on_progress_received from the stabilization args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - // need to incref this so it doesn't vanish later (borrowed reference we are saving) - Py_XINCREF(py_on_progress_received); - *py_progress_callback = py_on_progress_received; - - // Extract log_level - PyObject* py_log_level = PyDict_GetItemString(py_args, "log_level"); - if (py_log_level == NULL) - { - std::string message = "ParseArgs - Unable to retrieve log_level from the args."; - p_py_logger->log_exception(GCODE_CONVERSION, message); - return false; - } - - int log_level_value = static_cast(PyLong_AsLong(py_log_level)); - // determine the log level as an index rather than as a value - args.log_level = p_py_logger->get_log_level_for_value(log_level_value); - - return true; -} diff --git a/PyArcWelder/py_arc_welder_extension.h b/PyArcWelder/py_arc_welder_extension.h index 2212748..b71f680 100644 --- a/PyArcWelder/py_arc_welder_extension.h +++ b/PyArcWelder/py_arc_welder_extension.h @@ -29,6 +29,7 @@ #include #endif #include +#include "py_arc_welder.h" #include "py_logger.h" #include "arc_welder.h" extern "C" @@ -41,76 +42,6 @@ extern "C" static PyObject* ConvertFile(PyObject* self, PyObject* args); } -struct py_gcode_arc_args { - py_gcode_arc_args() { - guid = ""; - source_path = ""; - target_path = ""; - 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_EXTREUDER; - allow_3d_arcs = DEFAULT_ALLOW_3D_ARCS; - allow_travel_arcs = DEFAULT_ALLOW_TRAVEL_ARCS; - log_level = 0; - } - py_gcode_arc_args( - std::string guid_, - std::string source_path_, - std::string target_path_, - 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 log_level_ - ) { - guid = guid_; - source_path = source_path_; - target_path = target_path_; - resolution_mm = resolution_mm_; - path_tolerance_percent = path_tolerance_percent_; - max_radius_mm = max_radius_mm_; - min_arc_segments = min_arc_segments_; - mm_per_arc_segment = mm_per_arc_segment_; - allow_3d_arcs = allow_3d_arcs_; - allow_travel_arcs = allow_travel_arcs_; - allow_dynamic_precision = allow_dynamic_precision_; - default_xyz_precision = default_xyz_precision_; - default_e_precision = default_e_precision_; - extrusion_rate_variance_percent = extrusion_rate_variance_percent_; - g90_g91_influences_extruder = g90_g91_influences_extruder_; - log_level = log_level_; - } - std::string guid; - std::string source_path; - std::string target_path; - double resolution_mm; - double path_tolerance_percent; - 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; - bool g90_g91_influences_extruder; - double max_radius_mm; - int min_arc_segments; - double mm_per_arc_segment; - int log_level; -}; - -static bool ParseArgs(PyObject* py_args, py_gcode_arc_args& args, PyObject** p_py_progress_callback); - // global logger py_logger* p_py_logger = NULL; /* -- cgit v1.2.3