Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FormerLurker/ArcWelderLib.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFormerLurker <hochgebe@gmail.com>2021-07-17 00:05:32 +0300
committerFormerLurker <hochgebe@gmail.com>2021-07-17 00:05:32 +0300
commit56ea16df55e0e37581688effac94e78ffc10f941 (patch)
treefe73a62fb484b8290550912562c1c8eca84aed9a
parent7e315a6ccf1d94802b396738bff015d98042bfa9 (diff)
Fix xyz and e precision in console app. Fix unix->windows line endings resulting in lower compression. Fix g2/g3 length calculation within statistics.
-rw-r--r--ArcWelder/arc_welder.cpp1676
-rw-r--r--ArcWelder/arc_welder.h4
-rw-r--r--ArcWelder/segmented_arc.cpp38
-rw-r--r--ArcWelder/segmented_shape.h1
-rw-r--r--ArcWelder/unwritten_command.h4
-rw-r--r--ArcWelderConsole/ArcWelderConsole.cpp55
-rw-r--r--ArcWelderInverseProcessor/marlin_2_arc.cpp8
-rw-r--r--GcodeProcessorLib/array_list.h22
-rw-r--r--GcodeProcessorLib/utilities.cpp32
-rw-r--r--GcodeProcessorLib/utilities.h3
10 files changed, 972 insertions, 871 deletions
diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp
index 0531a67..1e601e5 100644
--- a/ArcWelder/arc_welder.cpp
+++ b/ArcWelder/arc_welder.cpp
@@ -37,903 +37,941 @@
#include <version.h>
arc_welder::arc_welder(
- std::string source_path,
- std::string target_path,
- logger * log,
- double resolution_mm,
- double path_tolerance_percent,
- double max_radius,
- int min_arc_segments,
- double mm_per_arc_segment,
- bool g90_g91_influences_extruder,
- 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 max_gcode_length,
- int buffer_size,
- progress_callback callback) : current_arc_(
- DEFAULT_MIN_SEGMENTS,
- buffer_size,
- resolution_mm,
- path_tolerance_percent,
- max_radius,
- min_arc_segments,
- mm_per_arc_segment,
- allow_3d_arcs,
- default_xyz_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
- )
+ std::string source_path,
+ std::string target_path,
+ logger* log,
+ double resolution_mm,
+ double path_tolerance_percent,
+ double max_radius,
+ int min_arc_segments,
+ double mm_per_arc_segment,
+ bool g90_g91_influences_extruder,
+ 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 max_gcode_length,
+ int buffer_size,
+ progress_callback callback) : current_arc_(
+ DEFAULT_MIN_SEGMENTS,
+ buffer_size,
+ resolution_mm,
+ path_tolerance_percent,
+ max_radius,
+ min_arc_segments,
+ mm_per_arc_segment,
+ allow_3d_arcs,
+ default_xyz_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;
- info_logging_enabled_ = false;
- error_logging_enabled_ = false;
- verbose_logging_enabled_ = false;
-
- logger_type_ = 0;
- resolution_mm_ = resolution_mm;
- progress_callback_ = callback;
- verbose_output_ = false;
- source_path_ = source_path;
- target_path_ = target_path;
- gcode_position_args_ = get_args_(g90_g91_influences_extruder, buffer_size);
- allow_3d_arcs_ = allow_3d_arcs;
- allow_travel_arcs_ = allow_travel_arcs;
- allow_dynamic_precision_ = allow_dynamic_precision;
- extrusion_rate_variance_percent_ = extrusion_rate_variance_percent;
- notification_period_seconds = 1;
- lines_processed_ = 0;
- gcodes_processed_ = 0;
- file_size_ = 0;
- last_gcode_line_written_ = 0;
- points_compressed_ = 0;
- arcs_created_ = 0;
- arcs_aborted_by_flow_rate_ = 0;
- waiting_for_arc_ = false;
- previous_feedrate_ = -1;
- gcode_position_args_.set_num_extruders(8);
- previous_extrusion_rate_ = 0;
- for (int index = 0; index < 8; index++)
- {
- gcode_position_args_.retraction_lengths[0] = .0001;
- gcode_position_args_.z_lift_heights[0] = 0.001;
- gcode_position_args_.x_firmware_offsets[0] = 0.0;
- gcode_position_args_.y_firmware_offsets[0] = 0.0;
- }
-
- // We don't care about the printer settings, except for g91 influences extruder.
-
- p_source_position_ = new gcode_position(gcode_position_args_);
+ p_logger_ = log;
+ debug_logging_enabled_ = false;
+ info_logging_enabled_ = false;
+ error_logging_enabled_ = false;
+ verbose_logging_enabled_ = false;
+
+ logger_type_ = 0;
+ resolution_mm_ = resolution_mm;
+ progress_callback_ = callback;
+ verbose_output_ = false;
+ source_path_ = source_path;
+ target_path_ = target_path;
+ gcode_position_args_ = get_args_(g90_g91_influences_extruder, buffer_size);
+ allow_3d_arcs_ = allow_3d_arcs;
+ allow_travel_arcs_ = allow_travel_arcs;
+ allow_dynamic_precision_ = allow_dynamic_precision;
+ extrusion_rate_variance_percent_ = extrusion_rate_variance_percent;
+ notification_period_seconds = 1;
+ lines_processed_ = 0;
+ gcodes_processed_ = 0;
+ file_size_ = 0;
+ last_gcode_line_written_ = 0;
+ points_compressed_ = 0;
+ arcs_created_ = 0;
+ arcs_aborted_by_flow_rate_ = 0;
+ waiting_for_arc_ = false;
+ previous_feedrate_ = -1;
+ gcode_position_args_.set_num_extruders(8);
+ previous_extrusion_rate_ = 0;
+ for (int index = 0; index < 8; index++)
+ {
+ gcode_position_args_.retraction_lengths[0] = .0001;
+ gcode_position_args_.z_lift_heights[0] = 0.001;
+ gcode_position_args_.x_firmware_offsets[0] = 0.0;
+ gcode_position_args_.y_firmware_offsets[0] = 0.0;
+ }
+
+ // We don't care about the printer settings, except for g91 influences extruder.
+
+ p_source_position_ = new gcode_position(gcode_position_args_);
}
gcode_position_args arc_welder::get_args_(bool g90_g91_influences_extruder, int buffer_size)
{
- gcode_position_args args;
- // Configure gcode_position_args
- args.g90_influences_extruder = g90_g91_influences_extruder;
- if (buffer_size < 2)
- {
- buffer_size = 2;
- }
- args.position_buffer_size = buffer_size;
- args.autodetect_position = true;
- args.home_x = 0;
- args.home_x_none = true;
- args.home_y = 0;
- args.home_y_none = true;
- args.home_z = 0;
- args.home_z_none = true;
- args.shared_extruder = true;
- args.zero_based_extruder = true;
-
-
- args.default_extruder = 0;
- args.xyz_axis_default_mode = "absolute";
- args.e_axis_default_mode = "absolute";
- args.units_default = "millimeters";
- args.location_detection_commands = std::vector<std::string>();
- args.is_bound_ = false;
- args.is_circular_bed = false;
- args.x_min = -9999;
- args.x_max = 9999;
- args.y_min = -9999;
- args.y_max = 9999;
- args.z_min = -9999;
- args.z_max = 9999;
- return args;
+ gcode_position_args args;
+ // Configure gcode_position_args
+ args.g90_influences_extruder = g90_g91_influences_extruder;
+ if (buffer_size < 2)
+ {
+ buffer_size = 2;
+ }
+ args.position_buffer_size = buffer_size;
+ args.autodetect_position = true;
+ args.home_x = 0;
+ args.home_x_none = true;
+ args.home_y = 0;
+ args.home_y_none = true;
+ args.home_z = 0;
+ args.home_z_none = true;
+ args.shared_extruder = true;
+ args.zero_based_extruder = true;
+
+
+ args.default_extruder = 0;
+ args.xyz_axis_default_mode = "absolute";
+ args.e_axis_default_mode = "absolute";
+ args.units_default = "millimeters";
+ args.location_detection_commands = std::vector<std::string>();
+ args.is_bound_ = false;
+ args.is_circular_bed = false;
+ args.x_min = -9999;
+ args.x_max = 9999;
+ args.y_min = -9999;
+ args.y_max = 9999;
+ args.z_min = -9999;
+ args.z_max = 9999;
+ return args;
}
arc_welder::~arc_welder()
{
- delete p_source_position_;
+ delete p_source_position_;
}
void arc_welder::set_logger_type(int logger_type)
{
- logger_type_ = logger_type;
+ logger_type_ = logger_type;
}
void arc_welder::reset()
{
- p_logger_->log(logger_type_, DEBUG, "Resetting all tracking variables.");
- lines_processed_ = 0;
- gcodes_processed_ = 0;
- last_gcode_line_written_ = 0;
- file_size_ = 0;
- points_compressed_ = 0;
- arcs_created_ = 0;
- waiting_for_arc_ = false;
+ p_logger_->log(logger_type_, DEBUG, "Resetting all tracking variables.");
+ lines_processed_ = 0;
+ gcodes_processed_ = 0;
+ last_gcode_line_written_ = 0;
+ file_size_ = 0;
+ points_compressed_ = 0;
+ arcs_created_ = 0;
+ waiting_for_arc_ = false;
}
long arc_welder::get_file_size(const std::string& file_path)
{
- // Todo: Fix this function. This is a pretty weak implementation :(
- std::ifstream file(file_path.c_str(), std::ios::in | std::ios::binary);
- const long l = (long)file.tellg();
- file.seekg(0, std::ios::end);
- const long m = (long)file.tellg();
- file.close();
- return (m - l);
+ // Todo: Fix this function. This is a pretty weak implementation :(
+ std::ifstream file(file_path.c_str(), std::ios::in | std::ios::binary);
+ const long l = (long)file.tellg();
+ file.seekg(0, std::ios::end);
+ const long m = (long)file.tellg();
+ file.close();
+ return (m - l);
}
double arc_welder::get_next_update_time() const
{
- return clock() + (notification_period_seconds * CLOCKS_PER_SEC);
+ return clock() + (notification_period_seconds * CLOCKS_PER_SEC);
}
double arc_welder::get_time_elapsed(double start_clock, double end_clock)
{
- return static_cast<double>(end_clock - start_clock) / CLOCKS_PER_SEC;
+ return static_cast<double>(end_clock - start_clock) / CLOCKS_PER_SEC;
}
arc_welder_results arc_welder::process()
{
-arc_welder_results results;
- p_logger_->log(logger_type_, DEBUG, "Configuring logging settings.");
- verbose_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, VERBOSE);
- debug_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, DEBUG);
- info_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, INFO);
- error_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, ERROR);
-
- std::stringstream stream;
- // reset tracking variables
- reset();
- // local variable to hold the progress update return. If it's false, we will exit.
- bool continue_processing = true;
-
- p_logger_->log(logger_type_, DEBUG, "Configuring progress updates.");
- int read_lines_before_clock_check = 1000;
- double next_update_time = get_next_update_time();
- const clock_t start_clock = clock();
- p_logger_->log(logger_type_, DEBUG, "Getting source file size.");
- file_size_ = get_file_size(source_path_);
- stream.clear();
- 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.");
- gcodeFile.open(source_path_.c_str(), std::ifstream::in);
- if (!gcodeFile.is_open())
- {
- results.success = false;
- results.message = "Unable to open the source file.";
- p_logger_->log_exception(logger_type_, results.message);
- return results;
- }
- p_logger_->log(logger_type_, DEBUG, "Source file opened successfully.");
-
- p_logger_->log(logger_type_, DEBUG, "Opening the target file for writing.");
-
- output_file_.open(target_path_.c_str(), std::ifstream::out);
- if (!output_file_.is_open())
- {
- results.success = false;
- results.message = "Unable to open the target file.";
- p_logger_->log_exception(logger_type_, results.message);
- gcodeFile.close();
- return results;
- }
-
- p_logger_->log(logger_type_, DEBUG, "Target file opened successfully.");
- std::string line;
- int lines_with_no_commands = 0;
- parsed_command cmd;
- // Communicate every second
- p_logger_->log(logger_type_, DEBUG, "Sending initial progress update.");
- continue_processing = on_progress_(get_progress_(static_cast<long>(gcodeFile.tellg()), static_cast<double>(start_clock)));
- p_logger_->log(logger_type_, DEBUG, "Processing source file.");
-
- bool arc_Welder_comment_added = false;
- while (std::getline(gcodeFile, line) && continue_processing)
- {
- lines_processed_++;
- // Check the first line of gcode and see if it = ;FLAVOR:UltiGCode
+ arc_welder_results results;
+ p_logger_->log(logger_type_, DEBUG, "Configuring logging settings.");
+ verbose_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, VERBOSE);
+ debug_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, DEBUG);
+ info_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, INFO);
+ error_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, ERROR);
+
+ std::stringstream stream;
+ // reset tracking variables
+ reset();
+ // local variable to hold the progress update return. If it's false, we will exit.
+ bool continue_processing = true;
+
+ p_logger_->log(logger_type_, DEBUG, "Configuring progress updates.");
+ int read_lines_before_clock_check = 1000;
+ double next_update_time = get_next_update_time();
+ const clock_t start_clock = clock();
+ p_logger_->log(logger_type_, DEBUG, "Getting source file size.");
+ file_size_ = get_file_size(source_path_);
+ stream.clear();
+ 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.");
+ gcodeFile.open(source_path_.c_str(), std::ifstream::in);
+ if (!gcodeFile.is_open())
+ {
+ results.success = false;
+ results.message = "Unable to open the source file.";
+ p_logger_->log_exception(logger_type_, results.message);
+ return results;
+ }
+ p_logger_->log(logger_type_, DEBUG, "Source file opened successfully.");
+
+ p_logger_->log(logger_type_, DEBUG, "Opening the target file for writing.");
+
+ output_file_.open(target_path_.c_str(), std::ios_base::binary | std::ios_base::out);
+ if (!output_file_.is_open())
+ {
+ results.success = false;
+ results.message = "Unable to open the target file.";
+ p_logger_->log_exception(logger_type_, results.message);
+ gcodeFile.close();
+ return results;
+ }
+
+ p_logger_->log(logger_type_, DEBUG, "Target file opened successfully.");
+ std::string line;
+ int lines_with_no_commands = 0;
+ parsed_command cmd;
+ // Communicate every second
+ p_logger_->log(logger_type_, DEBUG, "Sending initial progress update.");
+ continue_processing = on_progress_(get_progress_(static_cast<long>(gcodeFile.tellg()), static_cast<double>(start_clock)));
+ p_logger_->log(logger_type_, DEBUG, "Processing source file.");
+
+ bool arc_Welder_comment_added = false;
+ while (std::getline(gcodeFile, line) && continue_processing)
+ {
+ lines_processed_++;
+ // Check the first line of gcode and see if it = ;FLAVOR:UltiGCode
// This comment MUST be preserved as the first line for ultimakers, else things won't work
- if (lines_processed_ == 1)
- {
- bool isUltiGCode = line == ";FLAVOR:UltiGCode";
- bool isPrusaSlicer = line.rfind("; generated by PrusaSlicer", 0) == 0;
- if (isUltiGCode || isPrusaSlicer)
- {
- write_gcode_to_file(line);
- }
- add_arcwelder_comment_to_target();
- if (isUltiGCode || isPrusaSlicer)
- {
- lines_with_no_commands++;
- continue;
- }
- }
-
-
- cmd.clear();
- if (verbose_logging_enabled_)
- {
- stream.clear();
- stream.str("");
- stream << "Parsing: " << line;
- p_logger_->log(logger_type_, VERBOSE, stream.str());
- }
- parser_.try_parse_gcode(line.c_str(), cmd, true);
- bool has_gcode = false;
- if (cmd.gcode.length() > 0)
- {
- has_gcode = true;
- gcodes_processed_++;
- }
- else
- {
- lines_with_no_commands++;
- }
-
- // Always process the command through the printer, even if no command is found
- // This is important so that comments can be analyzed
- //std::cout << "stabilization::process_file - updating position...";
- process_gcode(cmd, false, false);
-
- // Only continue to process if we've found a command and either a progress_callback_ is supplied, or debug loggin is enabled.
- if (has_gcode)
- {
- if ((lines_processed_ % read_lines_before_clock_check) == 0 && next_update_time < clock())
- {
- if (verbose_logging_enabled_)
- {
- p_logger_->log(logger_type_, VERBOSE, "Sending progress update.");
- }
- continue_processing = on_progress_(get_progress_(static_cast<long>(gcodeFile.tellg()), static_cast<double>(start_clock)));
- next_update_time = get_next_update_time();
- }
- }
- }
-
- if (current_arc_.is_shape() && waiting_for_arc_)
- {
- p_logger_->log(logger_type_, DEBUG, "Processing the final line.");
- process_gcode(cmd, true, false);
- }
- 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<long>(file_size_), static_cast<double>(start_clock));
- if (debug_logging_enabled_)
- {
- p_logger_->log(logger_type_, DEBUG, "Sending final progress update message.");
- }
- on_progress_(final_progress);
-
- p_logger_->log(logger_type_, DEBUG, "Closing source and target files.");
- output_file_.close();
- gcodeFile.close();
-
- 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;
- p_logger_->log(logger_type_, DEBUG, "Returning processing results.");
-
- return results;
+ if (lines_processed_ == 1)
+ {
+ bool isUltiGCode = line == ";FLAVOR:UltiGCode";
+ bool isPrusaSlicer = line.rfind("; generated by PrusaSlicer", 0) == 0;
+ if (isUltiGCode || isPrusaSlicer)
+ {
+ write_gcode_to_file(line);
+ }
+ add_arcwelder_comment_to_target();
+ if (isUltiGCode || isPrusaSlicer)
+ {
+ lines_with_no_commands++;
+ continue;
+ }
+ }
+
+
+ cmd.clear();
+ if (verbose_logging_enabled_)
+ {
+ stream.clear();
+ stream.str("");
+ stream << "Parsing: " << line;
+ p_logger_->log(logger_type_, VERBOSE, stream.str());
+ }
+ parser_.try_parse_gcode(line.c_str(), cmd, true);
+ bool has_gcode = false;
+ if (cmd.gcode.length() > 0)
+ {
+ has_gcode = true;
+ gcodes_processed_++;
+ }
+ else
+ {
+ lines_with_no_commands++;
+ }
+
+ // Always process the command through the printer, even if no command is found
+ // This is important so that comments can be analyzed
+ //std::cout << "stabilization::process_file - updating position...";
+ process_gcode(cmd, false, false);
+
+ // Only continue to process if we've found a command and either a progress_callback_ is supplied, or debug loggin is enabled.
+ if (has_gcode)
+ {
+ if ((lines_processed_ % read_lines_before_clock_check) == 0 && next_update_time < clock())
+ {
+ if (verbose_logging_enabled_)
+ {
+ p_logger_->log(logger_type_, VERBOSE, "Sending progress update.");
+ }
+ continue_processing = on_progress_(get_progress_(static_cast<long>(gcodeFile.tellg()), static_cast<double>(start_clock)));
+ next_update_time = get_next_update_time();
+ }
+ }
+ }
+
+ if (current_arc_.is_shape() && waiting_for_arc_)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Processing the final line.");
+ process_gcode(cmd, true, false);
+ }
+ 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<long>(file_size_), static_cast<double>(start_clock));
+ if (debug_logging_enabled_)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Sending final progress update message.");
+ }
+ on_progress_(final_progress);
+
+ p_logger_->log(logger_type_, DEBUG, "Closing source and target files.");
+ output_file_.close();
+ gcodeFile.close();
+
+ 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;
+ p_logger_->log(logger_type_, DEBUG, "Returning processing results.");
+
+ return results;
}
bool arc_welder::on_progress_(const arc_welder_progress& progress)
{
- if (progress_callback_ != NULL)
- {
- return progress_callback_(progress, p_logger_, logger_type_);
- }
- else if (info_logging_enabled_)
- {
- p_logger_->log(logger_type_, INFO, progress.str());
- }
-
- return true;
+ if (progress_callback_ != NULL)
+ {
+ return progress_callback_(progress, p_logger_, logger_type_);
+ }
+ else if (info_logging_enabled_)
+ {
+ p_logger_->log(logger_type_, INFO, progress.str());
+ }
+
+ return true;
}
arc_welder_progress arc_welder::get_progress_(long source_file_position, double start_clock)
{
- arc_welder_progress progress;
- progress.gcodes_processed = gcodes_processed_;
- progress.lines_processed = lines_processed_;
- progress.points_compressed = points_compressed_;
- progress.arcs_created = arcs_created_;
- progress.arcs_aborted_by_flow_rate = arcs_aborted_by_flow_rate_;
- progress.source_file_position = source_file_position;
- progress.target_file_size = static_cast<long>(output_file_.tellp());
- progress.source_file_size = file_size_;
- long bytesRemaining = file_size_ - static_cast<long>(source_file_position);
- progress.percent_complete = static_cast<double>(source_file_position) / static_cast<double>(file_size_) * 100.0;
- progress.seconds_elapsed = get_time_elapsed(start_clock, clock());
- double bytesPerSecond = static_cast<double>(source_file_position) / progress.seconds_elapsed;
- progress.seconds_remaining = bytesRemaining / bytesPerSecond;
-
- if (source_file_position > 0) {
- progress.compression_ratio = (static_cast<float>(source_file_position) / static_cast<float>(progress.target_file_size));
- progress.compression_percent = (1.0 - (static_cast<float>(progress.target_file_size) / static_cast<float>(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;
-
+ arc_welder_progress progress;
+ progress.gcodes_processed = gcodes_processed_;
+ progress.lines_processed = lines_processed_;
+ progress.points_compressed = points_compressed_;
+ progress.arcs_created = arcs_created_;
+ progress.arcs_aborted_by_flow_rate = arcs_aborted_by_flow_rate_;
+ progress.source_file_position = source_file_position;
+ progress.target_file_size = static_cast<long>(output_file_.tellp());
+ progress.source_file_size = file_size_;
+ long bytesRemaining = file_size_ - static_cast<long>(source_file_position);
+ progress.percent_complete = static_cast<double>(source_file_position) / static_cast<double>(file_size_) * 100.0;
+ progress.seconds_elapsed = get_time_elapsed(start_clock, clock());
+ double bytesPerSecond = static_cast<double>(source_file_position) / progress.seconds_elapsed;
+ progress.seconds_remaining = bytesRemaining / bytesPerSecond;
+
+ if (source_file_position > 0) {
+ progress.compression_ratio = (static_cast<float>(source_file_position) / static_cast<float>(progress.target_file_size));
+ progress.compression_percent = (1.0 - (static_cast<float>(progress.target_file_size) / static_cast<float>(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;
+
}
int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess)
{
- /* use to catch gcode for debugging since I can't set conditions equal to strings
- if (cmd.gcode == "G1 X118.762 Y104.054 E0.0163")
- {
- std::cout << "Found it!";
- }
- */
- // Update the position for the source gcode file
- p_source_position_->update(cmd, lines_processed_, gcodes_processed_, -1);
- position* p_cur_pos = p_source_position_->get_current_position_ptr();
- position* p_pre_pos = p_source_position_->get_previous_position_ptr();
- bool is_previous_extruder_relative = p_pre_pos->is_extruder_relative;
- extruder extruder_current = p_cur_pos->get_current_extruder();
- extruder previous_extruder = p_pre_pos->get_current_extruder();
-
- //std::cout << lines_processed_ << " - " << cmd.gcode << ", CurrentEAbsolute: " << cur_extruder.e <<", ExtrusionLength: " << cur_extruder.extrusion_length << ", Retraction Length: " << cur_extruder.retraction_length << ", IsExtruding: " << cur_extruder.is_extruding << ", IsRetracting: " << cur_extruder.is_retracting << ".\n";
-
- int lines_written = 0;
- // see if this point is an extrusion
-
- bool arc_added = false;
- bool clear_shapes = false;
- double movement_length_mm = 0;
- bool has_e_changed = extruder_current.e_relative != 0;
- // Update the source file statistics
- if (p_cur_pos->has_xy_position_changed)
- {
- if (allow_3d_arcs_) {
- movement_length_mm = utilities::get_cartesian_distance(p_pre_pos->x, p_pre_pos->y, p_pre_pos->z, p_cur_pos->x, p_cur_pos->y, p_cur_pos->z);
- }
- else {
- movement_length_mm = utilities::get_cartesian_distance(p_pre_pos->x, p_pre_pos->y, p_cur_pos->x, p_cur_pos->y);
- }
-
- if (movement_length_mm > 0)
- {
- if (!is_reprocess)
- {
- if (has_e_changed)
- {
- segment_statistics_.update(movement_length_mm, true);
- }
- else if (allow_3d_arcs_)
- {
- travel_statistics_.update(movement_length_mm, true);
- }
-
- }
- }
- }
-
- // calculate the extrusion rate (mm/mm) and see how much it changes
- double mm_extruded_per_mm_travel = 0;
- double extrusion_rate_change_percent = 0;
- bool aborted_by_flow_rate = false;
- // TODO: MAKE SURE THIS WORKS FOR TRANSITIONS FROM TRAVEL TO NON TRAVEL MOVES
- if (movement_length_mm > 0 && has_e_changed)
- {
- mm_extruded_per_mm_travel = extruder_current.e_relative / movement_length_mm;
- if (previous_extrusion_rate_ > 0)
- {
- extrusion_rate_change_percent = std::fabs(utilities::get_percent_change(previous_extrusion_rate_, mm_extruded_per_mm_travel));
- }
- }
- if (previous_extrusion_rate_ != 0 && utilities::greater_than(extrusion_rate_change_percent, extrusion_rate_variance_percent_))
- {
- arcs_aborted_by_flow_rate_++;
- aborted_by_flow_rate = true;
- }
-
- // 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_g0_g1 = cmd.command == "G0" || cmd.command == "G1";
- if (allow_dynamic_precision_ && is_g0_g1)
- {
- for (std::vector<parsed_command_parameter>::iterator it = cmd.parameters.begin(); it != cmd.parameters.end(); ++it)
- {
- switch ((*it).name[0])
- {
- case 'X':
- case 'Y':
- case 'Z':
- current_arc_.update_xyz_precision((*it).double_precision);
- break;
- case 'E':
- current_arc_.update_e_precision((*it).double_precision);
- break;
- }
- }
- }
-
- bool z_axis_ok = allow_3d_arcs_ ||
- utilities::is_equal(p_cur_pos->z, p_pre_pos->z);
-
- if (
- !is_end && cmd.is_known_command && !cmd.is_empty && (
- 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) &&
- utilities::is_equal(p_cur_pos->x_firmware_offset, p_pre_pos->x_firmware_offset) &&
- utilities::is_equal(p_cur_pos->y_firmware_offset, p_pre_pos->y_firmware_offset) &&
- utilities::is_equal(p_cur_pos->z_firmware_offset, p_pre_pos->z_firmware_offset) &&
- (previous_extrusion_rate_ == 0 || utilities::less_than_or_equal(extrusion_rate_change_percent, extrusion_rate_variance_percent_)) &&
- !p_cur_pos->is_relative &&
- (
- !waiting_for_arc_ ||
- extruder_current.is_extruding ||
- // Test for travel conversion
- (allow_travel_arcs_ && p_cur_pos->is_travel()) ||
- //(previous_extruder.is_extruding && extruder_current.is_extruding) || // Test to see if
- // we can get more arcs.
- (previous_extruder.is_retracting && extruder_current.is_retracting)
- ) &&
- p_cur_pos->is_extruder_relative == is_previous_extruder_relative &&
- (!waiting_for_arc_ || p_pre_pos->f == p_cur_pos->f) && // might need to skip the waiting for arc check...
- (!waiting_for_arc_ || p_pre_pos->feature_type_tag == p_cur_pos->feature_type_tag)
- )
- ) {
-
- // 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.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_)
- {
- p_logger_->log(logger_type_, DEBUG, "Starting new arc from Gcode:" + cmd.gcode);
- }
- write_unwritten_gcodes_to_file();
- // add the previous point as the starting point for the current arc
- 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 << ")...";
-
- current_arc_.try_add_point(previous_p);
- }
-
- double e_relative = extruder_current.e_relative;
- int num_points = current_arc_.get_num_segments();
- arc_added = current_arc_.try_add_point(p);
- if (arc_added)
- {
- // Make sure our position list is large enough to handle all the segments
- if (current_arc_.get_num_segments()+2 > p_source_position_->get_max_positions())
- {
- p_source_position_->grow_max_positions(p_source_position_->get_max_positions()*2);
- }
- if (!waiting_for_arc_)
- {
- waiting_for_arc_ = true;
- previous_feedrate_ = p_pre_pos->f;
- }
- else
- {
- if (debug_logging_enabled_)
- {
- if (num_points+1 == current_arc_.get_num_segments())
- {
- p_logger_->log(logger_type_, DEBUG, "Adding point to arc from Gcode:" + cmd.gcode);
- }
-
- }
- }
- }
- }
- else {
-
- if (debug_logging_enabled_) {
- if (is_end)
- {
- p_logger_->log(logger_type_, DEBUG, "Procesing final shape, if one exists.");
- }
- else if (!cmd.is_empty)
- {
- if (!cmd.is_known_command)
- {
- p_logger_->log(logger_type_, DEBUG, "Command '" + cmd.command + "' is Unknown. Gcode:" + cmd.gcode);
- }
- else if (cmd.command != "G0" && cmd.command != "G1")
- {
- p_logger_->log(logger_type_, DEBUG, "Command '" + cmd.command + "' is not G0/G1, skipping. Gcode:" + cmd.gcode);
- }
- else if (!allow_3d_arcs_ && !utilities::is_equal(p_cur_pos->z, p_pre_pos->z))
- {
- p_logger_->log(logger_type_, DEBUG, "Z axis position changed, cannot convert:" + cmd.gcode);
- }
- else if (p_cur_pos->is_relative)
- {
- p_logger_->log(logger_type_, DEBUG, "XYZ Axis is in relative mode, cannot convert:" + cmd.gcode);
- }
- else if (
- waiting_for_arc_ && !(
- (previous_extruder.is_extruding && extruder_current.is_extruding) ||
- (previous_extruder.is_retracting && extruder_current.is_retracting)
- )
- )
- {
- std::string message = "Extruding or retracting state changed, cannot add point to current arc: " + cmd.gcode;
- if (verbose_logging_enabled_)
- {
-
- message.append(
- " - Verbose Info\n\tCurrent Position Info - Absolute E:" + utilities::to_string(extruder_current.e) +
- ", Offset E:" + utilities::to_string(extruder_current.get_offset_e()) +
- ", Mode:" + (p_cur_pos->is_extruder_relative_null ? "NULL" : p_cur_pos->is_extruder_relative ? "relative" : "absolute") +
- ", Retraction: " + utilities::to_string(extruder_current.retraction_length) +
- ", Extrusion: " + utilities::to_string(extruder_current.extrusion_length) +
- ", Retracting: " + (extruder_current.is_retracting ? "True" : "False") +
- ", Extruding: " + (extruder_current.is_extruding ? "True" : "False")
- );
- message.append(
- "\n\tPrevious Position Info - Absolute E:" + utilities::to_string(previous_extruder.e) +
- ", Offset E:" + utilities::to_string(previous_extruder.get_offset_e()) +
- ", Mode:" + (p_pre_pos->is_extruder_relative_null ? "NULL" : p_pre_pos->is_extruder_relative ? "relative" : "absolute") +
- ", Retraction: " + utilities::to_string(previous_extruder.retraction_length) +
- ", Extrusion: " + utilities::to_string(previous_extruder.extrusion_length) +
- ", Retracting: " + (previous_extruder.is_retracting ? "True" : "False") +
- ", Extruding: " + (previous_extruder.is_extruding ? "True" : "False")
- );
- p_logger_->log(logger_type_, VERBOSE, message);
- }
- else
- {
- p_logger_->log(logger_type_, DEBUG, message);
- }
-
- }
- else if (p_cur_pos->is_extruder_relative != p_pre_pos->is_extruder_relative)
- {
- p_logger_->log(logger_type_, DEBUG, "Extruder axis mode changed, cannot add point to current arc: " + cmd.gcode);
- }
- else if (waiting_for_arc_ && p_pre_pos->f != p_cur_pos->f)
- {
- p_logger_->log(logger_type_, DEBUG, "Feedrate changed, cannot add point to current arc: " + cmd.gcode);
- }
- else if (waiting_for_arc_ && p_pre_pos->feature_type_tag != p_cur_pos->feature_type_tag)
- {
- p_logger_->log(logger_type_, DEBUG, "Feature type changed, cannot add point to current arc: " + cmd.gcode);
- }
- else if (aborted_by_flow_rate)
- {
- std::stringstream stream;
- stream << std::fixed << std::setprecision(5);
- stream << "Arc Canceled - The extrusion rate variance of " << extrusion_rate_variance_percent_ << "% exceeded by " << extrusion_rate_change_percent - extrusion_rate_variance_percent_ <<"% on line " << lines_processed_ << ". Extruded " << extruder_current.e_relative << "mm over " << movement_length_mm << "mm of travel (" << mm_extruded_per_mm_travel << "mm/mm). Previous rate: " << previous_extrusion_rate_ << "mm/mm.";
- p_logger_->log(logger_type_, DEBUG, stream.str());
- }
- else
- {
- // Todo: Add all the relevant values
- p_logger_->log(logger_type_, DEBUG, "There was an unknown issue preventing the current point from being added to the arc: " + cmd.gcode);
- }
- }
- }
-
- // Reset the previous extrusion rate
- previous_extrusion_rate_ = 0;
- }
-
- if (!arc_added && !(cmd.is_empty && cmd.comment.length() == 0))
- {
- if (current_arc_.get_num_segments() < current_arc_.get_min_segments()) {
- if (debug_logging_enabled_ && !cmd.is_empty)
- {
- if (current_arc_.get_num_segments() != 0)
- {
- p_logger_->log(logger_type_, DEBUG, "Not enough segments, resetting. Gcode:" + cmd.gcode);
- }
-
- }
- waiting_for_arc_ = false;
- current_arc_.clear();
- }
- else if (waiting_for_arc_)
- {
-
- if (current_arc_.is_shape())
- {
- // 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->f);
- // Now clear the arc and flag the processor as not waiting for an arc
- waiting_for_arc_ = false;
- current_arc_.clear();
- p_cur_pos = NULL;
- p_pre_pos = NULL;
-
- // Reprocess this line
- if (!is_end)
- {
- return process_gcode(cmd, false, true);
- }
- else
- {
- if (debug_logging_enabled_)
- {
- p_logger_->log(logger_type_, DEBUG, "Final arc created, exiting.");
- }
- return 0;
- }
-
- }
- else
- {
- if (debug_logging_enabled_)
- {
- p_logger_->log(logger_type_, DEBUG, "The current arc is not a valid arc, resetting.");
- }
- current_arc_.clear();
- waiting_for_arc_ = false;
- }
- }
- else if (debug_logging_enabled_)
- {
- p_logger_->log(logger_type_, DEBUG, "Could not add point to arc from gcode:" + cmd.gcode);
- }
-
- }
-
- if (waiting_for_arc_ || !arc_added)
- {
- // 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, !has_e_changed && is_g0_g1, movement_length_mm));
-
- }
- else if (!waiting_for_arc_)
- {
- write_unwritten_gcodes_to_file();
- current_arc_.clear();
- }
- return lines_written;
+ /* use to catch gcode for debugging since I can't set conditions equal to strings
+ if (cmd.gcode == "G1 X118.762 Y104.054 E0.0163")
+ {
+ std::cout << "Found it!";
+ }
+ */
+ // Update the position for the source gcode file
+ p_source_position_->update(cmd, lines_processed_, gcodes_processed_, -1);
+ position* p_cur_pos = p_source_position_->get_current_position_ptr();
+ position* p_pre_pos = p_source_position_->get_previous_position_ptr();
+ bool is_previous_extruder_relative = p_pre_pos->is_extruder_relative;
+ extruder extruder_current = p_cur_pos->get_current_extruder();
+ extruder previous_extruder = p_pre_pos->get_current_extruder();
+
+ // Determine if this is a G0, G1, G2 or G3
+ bool is_g0_g1 = cmd.command == "G0" || cmd.command == "G1";
+ bool is_g2_g3 = cmd.command == "G2" || cmd.command == "G3";
+ //std::cout << lines_processed_ << " - " << cmd.gcode << ", CurrentEAbsolute: " << cur_extruder.e <<", ExtrusionLength: " << cur_extruder.extrusion_length << ", Retraction Length: " << cur_extruder.retraction_length << ", IsExtruding: " << cur_extruder.is_extruding << ", IsRetracting: " << cur_extruder.is_retracting << ".\n";
+
+ int lines_written = 0;
+ // see if this point is an extrusion
+
+ bool arc_added = false;
+ bool clear_shapes = false;
+ double movement_length_mm = 0;
+ bool has_e_changed = extruder_current.e_relative != 0;
+ // Update the source file statistics
+ if (p_cur_pos->has_xy_position_changed)
+ {
+ // If this is a g2/g3 command, we need to do a bit more to get the length of the arc.
+ // The movement_length_mm variable will contain the chord length, which we will need
+ if (is_g2_g3)
+ {
+ // Determine the radius of the arc, which is necessary to calculate the arc length from the chord length.
+ double i = 0;
+ double j = 0;
+ double r = 0;
+ // Iterate through the parameters and fill in I, J and R;
+ for (std::vector<parsed_command_parameter>::iterator it = cmd.parameters.begin(); it != cmd.parameters.end(); ++it)
+ {
+ switch ((*it).name[0])
+ {
+ case 'I':
+ i = (*it).double_precision;
+ break;
+ case 'J':
+ j = (*it).double_precision;
+ break;
+ // Note that the R form isn't fully implemented!
+ case 'R':
+ r = (*it).double_precision;
+ break;
+ }
+ }
+
+ // Calculate R
+ if (r == 0)
+ {
+ r = std::sqrt(i * i + j * j);
+ }
+ // Now we know the radius and the chord length;
+ movement_length_mm = utilities::get_arc_distance(p_pre_pos->x, p_pre_pos->y, p_pre_pos->z, p_cur_pos->x, p_cur_pos->y, p_cur_pos->z, i, j, r, p_cur_pos->command.command == "G2");
+
+ }
+ else if (allow_3d_arcs_) {
+ movement_length_mm = utilities::get_cartesian_distance(p_pre_pos->x, p_pre_pos->y, p_pre_pos->z, p_cur_pos->x, p_cur_pos->y, p_cur_pos->z);
+ }
+ else {
+ movement_length_mm = utilities::get_cartesian_distance(p_pre_pos->x, p_pre_pos->y, p_cur_pos->x, p_cur_pos->y);
+ }
+
+ if (movement_length_mm > 0)
+ {
+ if (!is_reprocess)
+ {
+ if (has_e_changed)
+ {
+ segment_statistics_.update(movement_length_mm, true);
+ }
+ else if (allow_travel_arcs_)
+ {
+ travel_statistics_.update(movement_length_mm, true);
+ }
+
+ }
+ }
+ }
+
+ // calculate the extrusion rate (mm/mm) and see how much it changes
+ double mm_extruded_per_mm_travel = 0;
+ double extrusion_rate_change_percent = 0;
+ bool aborted_by_flow_rate = false;
+ // TODO: MAKE SURE THIS WORKS FOR TRANSITIONS FROM TRAVEL TO NON TRAVEL MOVES
+ if (movement_length_mm > 0 && has_e_changed)
+ {
+ mm_extruded_per_mm_travel = extruder_current.e_relative / movement_length_mm;
+ if (previous_extrusion_rate_ > 0)
+ {
+ extrusion_rate_change_percent = std::fabs(utilities::get_percent_change(previous_extrusion_rate_, mm_extruded_per_mm_travel));
+ }
+ }
+ if (previous_extrusion_rate_ != 0 && utilities::greater_than(extrusion_rate_change_percent, extrusion_rate_variance_percent_))
+ {
+ arcs_aborted_by_flow_rate_++;
+ aborted_by_flow_rate = true;
+ }
+
+ // We need to make sure the printer is using absolute xyz, is extruding, and the extruder axis mode is the same as that of the previous position
+ // TODO: Handle relative XYZ axis. This is possible, but maybe not so important.
+
+ if (allow_dynamic_precision_ && is_g0_g1)
+ {
+ for (std::vector<parsed_command_parameter>::iterator it = cmd.parameters.begin(); it != cmd.parameters.end(); ++it)
+ {
+ switch ((*it).name[0])
+ {
+ case 'X':
+ case 'Y':
+ case 'Z':
+ current_arc_.update_xyz_precision((*it).double_precision);
+ break;
+ case 'E':
+ current_arc_.update_e_precision((*it).double_precision);
+ break;
+ }
+ }
+ }
+
+ bool z_axis_ok = allow_3d_arcs_ ||
+ utilities::is_equal(p_cur_pos->z, p_pre_pos->z);
+
+ if (
+ !is_end && cmd.is_known_command && !cmd.is_empty && (
+ 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) &&
+ utilities::is_equal(p_cur_pos->x_firmware_offset, p_pre_pos->x_firmware_offset) &&
+ utilities::is_equal(p_cur_pos->y_firmware_offset, p_pre_pos->y_firmware_offset) &&
+ utilities::is_equal(p_cur_pos->z_firmware_offset, p_pre_pos->z_firmware_offset) &&
+ (previous_extrusion_rate_ == 0 || utilities::less_than_or_equal(extrusion_rate_change_percent, extrusion_rate_variance_percent_)) &&
+ !p_cur_pos->is_relative &&
+ (
+ !waiting_for_arc_ ||
+ extruder_current.is_extruding ||
+ // Test for travel conversion
+ (allow_travel_arcs_ && p_cur_pos->is_travel()) ||
+ //(previous_extruder.is_extruding && extruder_current.is_extruding) || // Test to see if
+ // we can get more arcs.
+ (previous_extruder.is_retracting && extruder_current.is_retracting)
+ ) &&
+ p_cur_pos->is_extruder_relative == is_previous_extruder_relative &&
+ (!waiting_for_arc_ || p_pre_pos->f == p_cur_pos->f) && // might need to skip the waiting for arc check...
+ (!waiting_for_arc_ || p_pre_pos->feature_type_tag == p_cur_pos->feature_type_tag)
+ )
+ ) {
+
+ // 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.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_)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Starting new arc from Gcode:" + cmd.gcode);
+ }
+ write_unwritten_gcodes_to_file();
+ // add the previous point as the starting point for the current arc
+ 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 << ")...";
+
+ current_arc_.try_add_point(previous_p);
+ }
+
+ double e_relative = extruder_current.e_relative;
+ int num_points = current_arc_.get_num_segments();
+ arc_added = current_arc_.try_add_point(p);
+ if (arc_added)
+ {
+ // Make sure our position list is large enough to handle all the segments
+ if (current_arc_.get_num_segments() + 2 > p_source_position_->get_max_positions())
+ {
+ p_source_position_->grow_max_positions(p_source_position_->get_max_positions() * 2);
+ }
+ if (!waiting_for_arc_)
+ {
+ waiting_for_arc_ = true;
+ previous_feedrate_ = p_pre_pos->f;
+ }
+ else
+ {
+ if (debug_logging_enabled_)
+ {
+ if (num_points + 1 == current_arc_.get_num_segments())
+ {
+ p_logger_->log(logger_type_, DEBUG, "Adding point to arc from Gcode:" + cmd.gcode);
+ }
+
+ }
+ }
+ }
+ }
+ else {
+
+ if (debug_logging_enabled_) {
+ if (is_end)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Procesing final shape, if one exists.");
+ }
+ else if (!cmd.is_empty)
+ {
+ if (!cmd.is_known_command)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Command '" + cmd.command + "' is Unknown. Gcode:" + cmd.gcode);
+ }
+ else if (cmd.command != "G0" && cmd.command != "G1")
+ {
+ p_logger_->log(logger_type_, DEBUG, "Command '" + cmd.command + "' is not G0/G1, skipping. Gcode:" + cmd.gcode);
+ }
+ else if (!allow_3d_arcs_ && !utilities::is_equal(p_cur_pos->z, p_pre_pos->z))
+ {
+ p_logger_->log(logger_type_, DEBUG, "Z axis position changed, cannot convert:" + cmd.gcode);
+ }
+ else if (p_cur_pos->is_relative)
+ {
+ p_logger_->log(logger_type_, DEBUG, "XYZ Axis is in relative mode, cannot convert:" + cmd.gcode);
+ }
+ else if (
+ waiting_for_arc_ && !(
+ (previous_extruder.is_extruding && extruder_current.is_extruding) ||
+ (previous_extruder.is_retracting && extruder_current.is_retracting)
+ )
+ )
+ {
+ std::string message = "Extruding or retracting state changed, cannot add point to current arc: " + cmd.gcode;
+ if (verbose_logging_enabled_)
+ {
+
+ message.append(
+ " - Verbose Info\n\tCurrent Position Info - Absolute E:" + utilities::to_string(extruder_current.e) +
+ ", Offset E:" + utilities::to_string(extruder_current.get_offset_e()) +
+ ", Mode:" + (p_cur_pos->is_extruder_relative_null ? "NULL" : p_cur_pos->is_extruder_relative ? "relative" : "absolute") +
+ ", Retraction: " + utilities::to_string(extruder_current.retraction_length) +
+ ", Extrusion: " + utilities::to_string(extruder_current.extrusion_length) +
+ ", Retracting: " + (extruder_current.is_retracting ? "True" : "False") +
+ ", Extruding: " + (extruder_current.is_extruding ? "True" : "False")
+ );
+ message.append(
+ "\n\tPrevious Position Info - Absolute E:" + utilities::to_string(previous_extruder.e) +
+ ", Offset E:" + utilities::to_string(previous_extruder.get_offset_e()) +
+ ", Mode:" + (p_pre_pos->is_extruder_relative_null ? "NULL" : p_pre_pos->is_extruder_relative ? "relative" : "absolute") +
+ ", Retraction: " + utilities::to_string(previous_extruder.retraction_length) +
+ ", Extrusion: " + utilities::to_string(previous_extruder.extrusion_length) +
+ ", Retracting: " + (previous_extruder.is_retracting ? "True" : "False") +
+ ", Extruding: " + (previous_extruder.is_extruding ? "True" : "False")
+ );
+ p_logger_->log(logger_type_, VERBOSE, message);
+ }
+ else
+ {
+ p_logger_->log(logger_type_, DEBUG, message);
+ }
+
+ }
+ else if (p_cur_pos->is_extruder_relative != p_pre_pos->is_extruder_relative)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Extruder axis mode changed, cannot add point to current arc: " + cmd.gcode);
+ }
+ else if (waiting_for_arc_ && p_pre_pos->f != p_cur_pos->f)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Feedrate changed, cannot add point to current arc: " + cmd.gcode);
+ }
+ else if (waiting_for_arc_ && p_pre_pos->feature_type_tag != p_cur_pos->feature_type_tag)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Feature type changed, cannot add point to current arc: " + cmd.gcode);
+ }
+ else if (aborted_by_flow_rate)
+ {
+ std::stringstream stream;
+ stream << std::fixed << std::setprecision(5);
+ stream << "Arc Canceled - The extrusion rate variance of " << extrusion_rate_variance_percent_ << "% exceeded by " << extrusion_rate_change_percent - extrusion_rate_variance_percent_ << "% on line " << lines_processed_ << ". Extruded " << extruder_current.e_relative << "mm over " << movement_length_mm << "mm of travel (" << mm_extruded_per_mm_travel << "mm/mm). Previous rate: " << previous_extrusion_rate_ << "mm/mm.";
+ p_logger_->log(logger_type_, DEBUG, stream.str());
+ }
+ else
+ {
+ // Todo: Add all the relevant values
+ p_logger_->log(logger_type_, DEBUG, "There was an unknown issue preventing the current point from being added to the arc: " + cmd.gcode);
+ }
+ }
+ }
+
+ // Reset the previous extrusion rate
+ previous_extrusion_rate_ = 0;
+ }
+
+ if (!arc_added && !(cmd.is_empty && cmd.comment.length() == 0))
+ {
+ if (current_arc_.get_num_segments() < current_arc_.get_min_segments()) {
+ if (debug_logging_enabled_ && !cmd.is_empty)
+ {
+ if (current_arc_.get_num_segments() != 0)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Not enough segments, resetting. Gcode:" + cmd.gcode);
+ }
+
+ }
+ waiting_for_arc_ = false;
+ current_arc_.clear();
+ }
+ else if (waiting_for_arc_)
+ {
+
+ if (current_arc_.is_shape())
+ {
+ // 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->f);
+ // Now clear the arc and flag the processor as not waiting for an arc
+ waiting_for_arc_ = false;
+ current_arc_.clear();
+ p_cur_pos = NULL;
+ p_pre_pos = NULL;
+
+ // Reprocess this line
+ if (!is_end)
+ {
+ return process_gcode(cmd, false, true);
+ }
+ else
+ {
+ if (debug_logging_enabled_)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Final arc created, exiting.");
+ }
+ return 0;
+ }
+
+ }
+ else
+ {
+ if (debug_logging_enabled_)
+ {
+ p_logger_->log(logger_type_, DEBUG, "The current arc is not a valid arc, resetting.");
+ }
+ current_arc_.clear();
+ waiting_for_arc_ = false;
+ }
+ }
+ else if (debug_logging_enabled_)
+ {
+ p_logger_->log(logger_type_, DEBUG, "Could not add point to arc from gcode:" + cmd.gcode);
+ }
+
+ }
+
+ if (waiting_for_arc_ || !arc_added)
+ {
+ // 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, !has_e_changed && (is_g0_g1 || is_g2_g3), movement_length_mm));
+
+ }
+ else if (!waiting_for_arc_)
+ {
+ write_unwritten_gcodes_to_file();
+ current_arc_.clear();
+ }
+ return lines_written;
}
void arc_welder::write_arc_gcodes(double current_feedrate)
{
- std::string comment = get_comment_for_arc();
- // remove the same number of unwritten gcodes as there are arc segments, minus 1 for the start point
- // Which isn't a movement
- // note, skip the first point, it is the starting point
- int num_segments = current_arc_.get_num_segments() - 1;
- for (int index = 0; index < num_segments; index++)
- {
- while (!unwritten_commands_.pop_back().is_g0_g1);
- }
-
- // Undo the current command, since it isn't included in the arc
- p_source_position_->undo_update();
-
- // Set the current feedrate if it is different, else set to 0 to indicate that no feedrate should be included
- if (previous_feedrate_ > 0 && previous_feedrate_ == current_feedrate) {
- current_feedrate = 0;
- }
-
- // Craete the arc gcode
- std::string gcode = get_arc_gcode(comment);
-
- if (debug_logging_enabled_)
- {
- char buffer[20];
- std::string message = "Arc created with ";
- sprintf(buffer, "%d", current_arc_.get_num_segments());
- message += buffer;
- message += " segments: ";
- message += gcode;
- p_logger_->log(logger_type_, DEBUG, message);
- }
-
- // Write everything that hasn't yet been written
- write_unwritten_gcodes_to_file();
-
- // Update the current extrusion statistics for the current arc gcode
- 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 comment = get_comment_for_arc();
+ // remove the same number of unwritten gcodes as there are arc segments, minus 1 for the start point
+ // Which isn't a movement
+ // note, skip the first point, it is the starting point
+ int num_segments = current_arc_.get_num_segments() - 1;
+ for (int index = 0; index < num_segments; index++)
+ {
+ while (!unwritten_commands_.pop_back().is_g0_g1);
+ }
+
+ // Undo the current command, since it isn't included in the arc
+ p_source_position_->undo_update();
+
+ // Set the current feedrate if it is different, else set to 0 to indicate that no feedrate should be included
+ if (previous_feedrate_ > 0 && previous_feedrate_ == current_feedrate) {
+ current_feedrate = 0;
+ }
+
+ // Craete the arc gcode
+ std::string gcode = get_arc_gcode(comment);
+
+ if (debug_logging_enabled_)
+ {
+ char buffer[20];
+ std::string message = "Arc created with ";
+ sprintf(buffer, "%d", current_arc_.get_num_segments());
+ message += buffer;
+ message += " segments: ";
+ message += gcode;
+ p_logger_->log(logger_type_, DEBUG, message);
+ }
+
+ // Write everything that hasn't yet been written
+ write_unwritten_gcodes_to_file();
+
+ // Update the current extrusion statistics for the current arc gcode
+ if (current_arc_.get_shape_e_relative() != 0)
+ {
+ segment_statistics_.update(current_arc_.get_shape_length(), false);
+
+ }
+ else if (allow_travel_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()
{
- // build a comment string from the commands making up the arc
- // We need to start with the first command entered.
- int comment_index = unwritten_commands_.count() - (current_arc_.get_num_segments() - 1);
- std::string comment;
- for (; comment_index < unwritten_commands_.count(); comment_index++)
- {
- std::string old_comment = unwritten_commands_[comment_index].comment;
- if (old_comment != comment && old_comment.length() > 0)
- {
- if (comment.length() > 0)
- {
- comment += " - ";
- }
- comment += old_comment;
- }
- }
- return comment;
+ // build a comment string from the commands making up the arc
+ // We need to start with the first command entered.
+ int comment_index = unwritten_commands_.count() - (current_arc_.get_num_segments() - 1);
+ std::string comment;
+ for (; comment_index < unwritten_commands_.count(); comment_index++)
+ {
+ std::string old_comment = unwritten_commands_[comment_index].comment;
+ if (old_comment != comment && old_comment.length() > 0)
+ {
+ if (comment.length() > 0)
+ {
+ comment += " - ";
+ }
+ comment += old_comment;
+ }
+ }
+ return comment;
}
std::string arc_welder::create_g92_e(double absolute_e)
{
- std::stringstream stream;
- stream << std::fixed << std::setprecision(5);
- stream << "G92 E" << absolute_e;
- return stream.str();
+ std::stringstream stream;
+ stream << std::fixed << std::setprecision(5);
+ stream << "G92 E" << absolute_e;
+ return stream.str();
}
int arc_welder::write_gcode_to_file(std::string gcode)
{
- output_file_ << gcode << "\n";
- return 1;
+ output_file_ << gcode << "\n";
+ return 1;
}
int arc_welder::write_unwritten_gcodes_to_file()
{
- int size = unwritten_commands_.count();
- std::string lines_to_write;
-
- for (int index = 0; index < size; index++)
- {
- // The the current unwritten position and remove it from the list
- unwritten_command p = unwritten_commands_.pop_front();
- if(p.is_g0_g1 && p.length > 0)
- {
- 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");
- }
-
- output_file_ << lines_to_write;
- return size;
+ int size = unwritten_commands_.count();
+ std::string lines_to_write;
+
+ for (int index = 0; index < size; index++)
+ {
+ // The the current unwritten position and remove it from the list
+ unwritten_command p = unwritten_commands_.pop_front();
+ if ((p.is_g0_g1 || p.is_g2_g3) && p.length > 0)
+ {
+ if (!p.is_travel)
+ {
+ segment_statistics_.update(p.length, false);
+ }
+ else if (allow_travel_arcs_) {
+ travel_statistics_.update(p.length, false);
+ }
+ }
+ lines_to_write.append(p.to_string()).append("\n");
+ }
+
+ output_file_ << lines_to_write;
+ return size;
}
std::string arc_welder::get_arc_gcode(const std::string comment)
{
- // Write gcode to file
- std::string gcode;
+ // Write gcode to file
+ std::string gcode;
- gcode = current_arc_.get_shape_gcode();
+ gcode = current_arc_.get_shape_gcode();
- if (comment.length() > 0)
- {
- gcode += ";" + comment;
- }
- return gcode;
+ if (comment.length() > 0)
+ {
+ gcode += ";" + comment;
+ }
+ return gcode;
}
void arc_welder::add_arcwelder_comment_to_target()
{
- p_logger_->log(logger_type_, DEBUG, "Adding ArcWelder comment to the target file.");
- std::stringstream stream;
- stream << std::fixed;
- stream << "; Postprocessed by [ArcWelder](https://github.com/FormerLurker/ArcWelderLib)\n";
- stream << "; Copyright(C) 2020 - Brad Hochgesang\n";
- stream << "; Version: " << GIT_TAGGED_VERSION << ", Branch: " << GIT_BRANCH << ", BuildDate: " << BUILD_DATE << "\n";
- stream << "; resolution=" << std::setprecision(2) << resolution_mm_ << "mm\n";
- stream << "; path_tolerance=" << std::setprecision(1) << (current_arc_.get_path_tolerance_percent() * 100.0) << "%\n";
- stream << "; max_radius=" << std::setprecision(2) << (current_arc_.get_max_radius()) << "mm\n";
- if (gcode_position_args_.g90_influences_extruder)
- {
- stream << "; g90_influences_extruder=True\n";
- }
- if (current_arc_.get_mm_per_arc_segment() > 0 && current_arc_.get_min_arc_segments() > 0)
- {
- stream << "; firmware_compensation=True\n";
- stream << "; mm_per_arc_segment="<< std::setprecision(2) << current_arc_.get_mm_per_arc_segment() << "mm\n";
- stream << "; min_arc_segments=" << std::setprecision(0) << current_arc_.get_min_arc_segments() << "\n";
- }
- if (allow_3d_arcs_)
- {
- stream << "; allow_3d_arcs=True\n";
-
- }
- if (allow_dynamic_precision_)
- {
- stream << "; allow_dynamic_precision=True\n";
- }
- stream << "; default_xyz_precision=" << std::setprecision(0) << static_cast<int>(current_arc_.get_xyz_precision()) << "\n";
- stream << "; default_e_precision=" << std::setprecision(0) << static_cast<int>(current_arc_.get_e_precision()) << "\n";
- stream << "; extrusion_rate_variance_percent=" << std::setprecision(1) << (extrusion_rate_variance_percent_ * 100.0) << "%\n\n";
-
-
- output_file_ << stream.str();
+ p_logger_->log(logger_type_, DEBUG, "Adding ArcWelder comment to the target file.");
+ std::stringstream stream;
+ stream << std::fixed;
+ stream << "; Postprocessed by [ArcWelder](https://github.com/FormerLurker/ArcWelderLib)\n";
+ stream << "; Copyright(C) 2020 - Brad Hochgesang\n";
+ stream << "; Version: " << GIT_TAGGED_VERSION << ", Branch: " << GIT_BRANCH << ", BuildDate: " << BUILD_DATE << "\n";
+ stream << "; resolution=" << std::setprecision(2) << resolution_mm_ << "mm\n";
+ stream << "; path_tolerance=" << std::setprecision(1) << (current_arc_.get_path_tolerance_percent() * 100.0) << "%\n";
+ stream << "; max_radius=" << std::setprecision(2) << (current_arc_.get_max_radius()) << "mm\n";
+ if (gcode_position_args_.g90_influences_extruder)
+ {
+ stream << "; g90_influences_extruder=True\n";
+ }
+ if (current_arc_.get_mm_per_arc_segment() > 0 && current_arc_.get_min_arc_segments() > 0)
+ {
+ stream << "; firmware_compensation=True\n";
+ stream << "; mm_per_arc_segment=" << std::setprecision(2) << current_arc_.get_mm_per_arc_segment() << "mm\n";
+ stream << "; min_arc_segments=" << std::setprecision(0) << current_arc_.get_min_arc_segments() << "\n";
+ }
+ if (allow_3d_arcs_)
+ {
+ stream << "; allow_3d_arcs=True\n";
+
+ }
+ if (allow_dynamic_precision_)
+ {
+ stream << "; allow_dynamic_precision=True\n";
+ }
+ stream << "; default_xyz_precision=" << std::setprecision(0) << static_cast<int>(current_arc_.get_xyz_precision()) << "\n";
+ stream << "; default_e_precision=" << std::setprecision(0) << static_cast<int>(current_arc_.get_e_precision()) << "\n";
+ stream << "; extrusion_rate_variance_percent=" << std::setprecision(1) << (extrusion_rate_variance_percent_ * 100.0) << "%\n\n";
+
+
+ output_file_ << stream.str();
}
diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h
index fc5bb84..ea10257 100644
--- a/ArcWelder/arc_welder.h
+++ b/ArcWelder/arc_welder.h
@@ -431,10 +431,8 @@ typedef bool(*progress_callback)(arc_welder_progress, logger* p_logger, int logg
#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_ALLOW_TRAVEL_ARCS true
#define DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT 0.05
-#define DEFAULT_CONVERT_TRAVEL_MOVES false
-
struct arc_welder_args
{
diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp
index 531c9e5..568d964 100644
--- a/ArcWelder/segmented_arc.cpp
+++ b/ArcWelder/segmented_arc.cpp
@@ -368,20 +368,38 @@ int segmented_arc::get_shape_gcode_length()
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_spaces = 4 + (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_decimals = xyz_precision * (4 + (has_z ? 1 : 0)) + e_precision * (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)
+ utilities::get_num_digits(current_arc_.end_point.x, xyz_precision) +
+ utilities::get_num_digits(current_arc_.end_point.y, xyz_precision) +
+ (has_z ? utilities::get_num_digits(current_arc_.end_point.z, xyz_precision) : 0) +
+ (has_e ? utilities::get_num_digits(e, e_precision) : 0) +
+ utilities::get_num_digits(i, xyz_precision) +
+ utilities::get_num_digits(j, xyz_precision) +
+ (has_f ? utilities::get_num_digits(f,0) : 0)
+ );
+ int num_minus_signs = (
+ (current_arc_.end_point.x < 0 ? 1 : 0) +
+ (current_arc_.end_point.y < 0 ? 1 : 0) +
+ (i < 0 ? 1 : 0) +
+ (j < 0 ? 1 : 0) +
+ (has_e && e < 0 ? 1 : 0) +
+ (has_z && current_arc_.end_point.z < 0 ? 1 : 0)
);
+
+ int num_parameters = 4 + (has_e ? 1 : 0) + (has_z ? 1: 0) + (has_f ? 1: 0);
// Return the length of the gcode.
- return 3 + num_spaces + num_decimal_points + num_decimal_points + num_digits;
+ int gcode_length = 2 + num_spaces + num_decimal_points + num_digits + num_minus_signs + num_decimals + num_parameters;
+ std::string gcode = get_shape_gcode();
+ if (gcode.length() != gcode_length)
+ {
+ return 10000;
+ }
+ return gcode_length;
diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h
index d5c88d5..d27a568 100644
--- a/ArcWelder/segmented_shape.h
+++ b/ArcWelder/segmented_shape.h
@@ -25,7 +25,6 @@
#pragma once
#include <string>
#include <limits>
-#define PI_DOUBLE 3.14159265358979323846264338327950288
#include <list>
#include "utilities.h"
diff --git a/ArcWelder/unwritten_command.h b/ArcWelder/unwritten_command.h
index d1ed490..5acf999 100644
--- a/ArcWelder/unwritten_command.h
+++ b/ArcWelder/unwritten_command.h
@@ -31,13 +31,15 @@ struct unwritten_command
is_extruder_relative = false;
length = 0;
is_g0_g1 = false;
+ is_g2_g3 = false;
}
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)
+ : is_extruder_relative(is_relative), is_travel(is_travel), is_g0_g1(cmd.command == "G0" || cmd.command == "G1"), is_g2_g3(cmd.command == "G2" || cmd.command == "G3"), gcode(cmd.gcode), comment(cmd.comment), length(command_length)
{
}
bool is_g0_g1;
+ bool is_g2_g3;
bool is_extruder_relative;
bool is_travel;
double length;
diff --git a/ArcWelderConsole/ArcWelderConsole.cpp b/ArcWelderConsole/ArcWelderConsole.cpp
index e7a1ea9..37574ea 100644
--- a/ArcWelderConsole/ArcWelderConsole.cpp
+++ b/ArcWelderConsole/ArcWelderConsole.cpp
@@ -91,7 +91,6 @@ int main(int argc, char* argv[])
arg_description_stream << "The maximum radius of any arc in mm. Default Value: " << DEFAULT_MAX_RADIUS_MM;
TCLAP::ValueArg<double> max_radius_arg("m", "max-radius-mm", arg_description_stream.str(), false, DEFAULT_MAX_RADIUS_MM, "float");
-
// -s --mm-per-arc-segment
arg_description_stream.clear();
arg_description_stream.str("");
@@ -132,13 +131,13 @@ int main(int argc, char* argv[])
arg_description_stream.clear();
arg_description_stream.str("");
arg_description_stream << "The default precision of X, Y, Z, I and J output gcode parameters. The precision may be larger than this value if allow-dynamic-precision is set to true. Default Value: " << DEFAULT_XYZ_PRECISION;
- TCLAP::ValueArg<unsigned char> default_xyz_precision_arg("x", "default-xyz-precision", arg_description_stream.str(), false, DEFAULT_XYZ_PRECISION, "unsigned char");
+ TCLAP::ValueArg<unsigned int> default_xyz_precision_arg("x", "default-xyz-precision", arg_description_stream.str(), false, DEFAULT_XYZ_PRECISION, "unsigned int");
// -e --default-e-precision
arg_description_stream.clear();
arg_description_stream.str("");
arg_description_stream << "The default precision of E output gcode parameters. The precision may be larger than this value if allow-dynamic-precision is set to true. Default Value: " << DEFAULT_E_PRECISION;
- TCLAP::ValueArg<unsigned char> default_e_precision_arg("e", "default-e-precision", arg_description_stream.str(), false, DEFAULT_E_PRECISION, "unsigned char");
+ TCLAP::ValueArg<unsigned int> default_e_precision_arg("e", "default-e-precision", arg_description_stream.str(), false, DEFAULT_E_PRECISION, "unsigned int");
// -v --extrusion-rate-variance
arg_description_stream.clear();
@@ -146,14 +145,13 @@ 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<double> 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
+ // -c --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<int> max_gcode_length_arg("l", "max-gcode-length", arg_description_stream.str(), false, DEFAULT_MAX_GCODE_LENGTH, "int");
+ TCLAP::ValueArg<int> max_gcode_length_arg("c", "max-gcode-length", arg_description_stream.str(), false, DEFAULT_MAX_GCODE_LENGTH, "int");
// -p --progress-type
- // -l --log-level
std::vector<std::string> progress_type_vector;
std::string progress_type_default_string = PROGRESS_TYPE_SIMPLE;
progress_type_vector.push_back(PROGRESS_TYPE_NONE);
@@ -181,6 +179,7 @@ int main(int argc, char* argv[])
arg_description_stream << "Sets console log level. Default Value: " << log_level_string_default;
TCLAP::ValueArg<std::string> log_level_arg("l", "log-level", arg_description_stream.str(), false, log_level_string_default, &log_levels_constraint);
+
// Add all arguments
cmd.add(source_arg);
cmd.add(target_arg);
@@ -221,8 +220,8 @@ int main(int argc, char* argv[])
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();
+ unsigned int xyz_precision = default_xyz_precision_arg.getValue();
+ unsigned int 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();
@@ -274,34 +273,38 @@ int main(int argc, char* argv[])
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 (args.default_xyz_precision < 3)
+ if (xyz_precision < 3)
{
// warning
- 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;
+ std::cout << "warning: The provided default_xyz_precision " << xyz_precision << "mm is less than 3, with will cause issues printing arcs. A value of 3 will be used instead." << std::endl;
+ xyz_precision = 3;
}
- if (args.default_e_precision < DEFAULT_E_PRECISION)
+ if (e_precision < DEFAULT_E_PRECISION)
{
// warning
- 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;
+ std::cout << "warning: The provided default_e_precision " << e_precision << "mm is less than 3, with will cause extrusion issues. A value of 3 will be used instead." << std::endl;
+ e_precision = 3;
}
- if (args.default_xyz_precision > 6)
+ if (xyz_precision > 6)
{
// warning
- 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;
+ std::cout << "warning: The provided default_xyz_precision " << 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;
+ xyz_precision = 6;
}
- if (args.default_e_precision > 6)
+ if (e_precision > 6)
{
// warning
- 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;
+ std::cout << "warning: The provided default_e_precision " << 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;
+ e_precision = 6;
}
+ // Fill in the adjusted precisions
+ args.default_e_precision = (unsigned char)e_precision;
+ args.default_xyz_precision = (unsigned char)xyz_precision;
+
if (args.extrusion_rate_variance_percent < 0)
{
// warning
@@ -312,7 +315,7 @@ int main(int argc, char* argv[])
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;
+ std::cout << "warning: The provided max_gcode_length " << args.max_gcode_length << " is less than 0. Setting to the default (no limit)." << std::endl;
args.max_gcode_length = DEFAULT_MAX_GCODE_LENGTH;
}
@@ -386,7 +389,15 @@ int main(int argc, char* argv[])
{
log_messages.clear();
log_messages.str("");
- log_messages << "Target File Travel Statistics:" << std::endl << results.progress.travel_statistics.str();
+ if (results.progress.travel_statistics.total_count_source == results.progress.travel_statistics.total_count_source)
+ {
+ log_messages << "Target File Travel Statistics: No travel arcs converted." ;
+ }
+ else
+ {
+ log_messages << "Target File Travel Statistics:" << std::endl << results.progress.travel_statistics.str();
+ }
+
p_logger->log(0, INFO, log_messages.str());
}
diff --git a/ArcWelderInverseProcessor/marlin_2_arc.cpp b/ArcWelderInverseProcessor/marlin_2_arc.cpp
index b7b3246..0656015 100644
--- a/ArcWelderInverseProcessor/marlin_2_arc.cpp
+++ b/ArcWelderInverseProcessor/marlin_2_arc.cpp
@@ -184,18 +184,18 @@ void marlin_2_arc::process()
target[Z_AXIS] = static_cast<float>(p_cur_pos->get_gcode_z());
target[E_AXIS] = static_cast<float>(p_cur_pos->get_current_extruder().get_offset_e());
float offset[2];
- offset[0] = 0.0;
- offset[1] = 0.0;
+ offset[X_AXIS] = 0.0;
+ offset[Y_AXIS] = 0.0;
for (unsigned int index = 0; index < cmd.parameters.size(); index++)
{
parsed_command_parameter p = cmd.parameters[index];
if (p.name == "I")
{
- offset[0] = static_cast<float>(p.double_value);
+ offset[X_AXIS] = static_cast<float>(p.double_value);
}
else if (p.name == "J")
{
- offset[1] = static_cast<float>(p.double_value);
+ offset[Y_AXIS] = static_cast<float>(p.double_value);
}
}
float radius = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc
diff --git a/GcodeProcessorLib/array_list.h b/GcodeProcessorLib/array_list.h
index 53ed43e..a69fc28 100644
--- a/GcodeProcessorLib/array_list.h
+++ b/GcodeProcessorLib/array_list.h
@@ -35,7 +35,7 @@ public:
count_ = 0;
items_ = new T[max_size_];
}
-
+
array_list(int max_size)
{
auto_grow_ = false;
@@ -44,11 +44,11 @@ public:
count_ = 0;
items_ = new T[max_size];
}
-
+
virtual ~array_list() {
delete[] items_;
}
-
+
void resize(int max_size)
{
T* new_items = new T[max_size];
@@ -71,7 +71,7 @@ public:
}
return index_position;
}
-
+
void push_front(T object)
{
if (count_ == max_size_)
@@ -93,7 +93,7 @@ public:
count_++;
items_[front_index_] = object;
}
-
+
void push_back(T object)
{
if (count_ == max_size_)
@@ -110,7 +110,7 @@ public:
items_[pos] = object;
count_++;
}
-
+
T& pop_front()
{
if (count_ == 0)
@@ -135,7 +135,7 @@ public:
{
throw std::exception();
}
- int pos = get_index_position(count_-1);
+ int pos = get_index_position(count_ - 1);
count_--;
return items_[pos];
}
@@ -151,23 +151,23 @@ public:
int opos = get_index_position(index);
return items_[opos];
}
-
+
int count() const
{
return count_;
}
-
+
int get_max_size() const
{
return max_size_;
}
-
+
void clear()
{
count_ = 0;
front_index_ = 0;
}
-
+
void copy(const array_list<T>& source)
{
if (max_size_ < source.max_size_)
diff --git a/GcodeProcessorLib/utilities.cpp b/GcodeProcessorLib/utilities.cpp
index 4db0f6a..e4b8526 100644
--- a/GcodeProcessorLib/utilities.cpp
+++ b/GcodeProcessorLib/utilities.cpp
@@ -87,6 +87,30 @@ double utilities::get_cartesian_distance(double x1, double y1, double z1, double
return std::sqrt(dist_squared);
}
+double utilities::get_arc_distance(double x1, double y1, double z1, double x2, double y2, double z2, double i, double j, double r, bool is_clockwise)
+{
+ double center_x = x1 - i;
+ double center_y = y1 - j;
+ double radius = hypot(i, j);
+ double z_dist = z2-z1;
+ double rt_x = x2 - center_x;
+ double rt_y = y2 - center_y;
+ double angular_travel_total = std::atan2(i * rt_y - j * rt_x, i * rt_x + j * rt_y);
+ if (angular_travel_total < 0) { angular_travel_total += (double)(2.0 * PI_DOUBLE); }
+ // Adjust the angular travel if the direction is clockwise
+ if (is_clockwise) { angular_travel_total -= (float)(2 * PI_DOUBLE); }
+ // Full circle fix.
+ if (x1 == x2 && y1 == y2 && angular_travel_total == 0)
+ {
+ angular_travel_total += (float)(2 * PI_DOUBLE);
+ }
+
+ // 20200417 - FormerLurker - rename millimeters_of_travel to millimeters_of_travel_arc to better describe what we are
+ // calculating here
+ return hypot(angular_travel_total * radius, std::fabs(z_dist));
+
+}
+
std::string utilities::to_string(double value)
{
std::ostringstream os;
@@ -220,6 +244,14 @@ int utilities::get_num_digits(int x)
(x < 10000000000 ? 10 : -1))))))))));
}
+int utilities::get_num_digits(double x, int precision)
+{
+ return get_num_digits(
+ (int) std::ceil(x * std::pow(10, (double)precision) - .4999999999999)
+ / std::pow(10, (double)precision)
+ );
+}
+
int utilities::get_num_digits(double x)
{
return get_num_digits((int) x);
diff --git a/GcodeProcessorLib/utilities.h b/GcodeProcessorLib/utilities.h
index 3261f91..cf3a97b 100644
--- a/GcodeProcessorLib/utilities.h
+++ b/GcodeProcessorLib/utilities.h
@@ -28,6 +28,7 @@
// Had to increase the zero tolerance because prusa slicer doesn't always
// retract enough while wiping.
#define ZERO_TOLERANCE 0.000005
+#define PI_DOUBLE 3.14159265358979323846264338327950288
class utilities{
public:
@@ -41,6 +42,7 @@ public:
static double get_cartesian_distance(double x1, double y1, double x2, double y2);
static double get_cartesian_distance(double x1, double y1, double z1, double x2, double y2, double z2);
+ static double get_arc_distance(double x1, double y1, double z1, double x2, double y2, double z2, double i, double j, double r, bool is_clockwise);
/* Todo: Implement for gcode comment processor
static bool case_insensitive_compare_char(char& c1, char& c2);
static bool case_insensitive_compare(std::string& str1, std::string& str2);
@@ -57,6 +59,7 @@ public:
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);
+ static int get_num_digits(double x, int precision);
static std::vector<std::string> splitpath(const std::string& str);
static bool get_file_path(const std::string& file_path, std::string& path);