From 4f2fef2779e4cac3d31eb2ba4181416efb6a6bab Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Fri, 20 Nov 2020 14:40:10 -0600 Subject: Add -z parameter to console app to support arcs, take z into account when calculating spiral length. --- ArcWelder/arc_welder.cpp | 28 +++++++++++++++++----------- ArcWelder/arc_welder.h | 2 +- ArcWelder/segmented_arc.cpp | 9 ++++++++- ArcWelder/segmented_arc.h | 2 +- ArcWelder/segmented_shape.cpp | 19 ++++++++++++++++++- ArcWelder/segmented_shape.h | 4 ++-- ArcWelderConsole/ArcWelderConsole.cpp | 11 ++++++++++- ArcWelderTest/ArcWelderTest.cpp | 9 +++++++-- ArcWelderTest/ArcWelderTest.h | 2 ++ GcodeProcessorLib/logger.cpp | 3 ++- PyArcWelder/py_arc_welder.h | 6 ++++-- PyArcWelder/py_arc_welder_extension.cpp | 19 ++++++++++++++++++- PyArcWelder/py_arc_welder_extension.h | 4 ++++ 13 files changed, 94 insertions(+), 24 deletions(-) diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp index 7f78c3c..c9cd465 100644 --- a/ArcWelder/arc_welder.cpp +++ b/ArcWelder/arc_welder.cpp @@ -188,7 +188,8 @@ arc_welder_results results; 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() << ", max_radius_mm:" << current_arc_.get_max_radius() - << ", g90_91_influences_extruder: " << (p_source_position_->get_g90_91_influences_extruder() ? "True" : "False"); + << ", g90_91_influences_extruder: " << (p_source_position_->get_g90_91_influences_extruder() ? "True" : "False") + << ", allow_z_axis_changes: " << (allow_z_axis_changes_ ? "True" : "False"); p_logger_->log(logger_type_, INFO, stream.str()); @@ -416,13 +417,12 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess } } + bool z_axis_ok = allow_z_axis_changes_ || + utilities::is_equal(p_cur_pos->z, p_pre_pos->z); + if ( !is_end && cmd.is_known_command && !cmd.is_empty && ( - is_g1_g2 && - ( - allow_z_axis_changes_ || - utilities::is_equal(p_cur_pos->z, p_pre_pos->z) - ) && + is_g1_g2 && 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) && @@ -474,9 +474,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess { p_logger_->log(logger_type_, DEBUG, "Adding point to arc from Gcode:" + cmd.gcode); } - { - p_logger_->log(logger_type_, DEBUG, "Removed start point from arc and added a new point from Gcode:" + cmd.gcode); - } + } } } @@ -561,7 +559,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess } } - if (!arc_added) + 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) @@ -690,7 +688,15 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess if (p_cur_pos->has_xy_position_changed && (cur_extruder.is_extruding || cur_extruder.is_retracting)) { position* prev_pos = p_source_position_->get_previous_position_ptr(); - length = utilities::get_cartesian_distance(cur_pos->x, cur_pos->y, prev_pos->x, prev_pos->y); + length = 0; + if (allow_z_axis_changes_) + { + length = utilities::get_cartesian_distance(cur_pos->x, cur_pos->y, cur_pos->z, prev_pos->x, prev_pos->y, prev_pos->z); + } + else { + length = utilities::get_cartesian_distance(cur_pos->x, cur_pos->y, prev_pos->x, prev_pos->y); + } + } unwritten_commands_.push_back(unwritten_command(cur_pos, length)); diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h index 0c2b3ea..5577267 100644 --- a/ArcWelder/arc_welder.h +++ b/ArcWelder/arc_welder.h @@ -407,7 +407,7 @@ struct arc_welder_results { std::string message; arc_welder_progress progress; }; -#define DEFAULT_GCODE_BUFFER_SIZE 100 +#define DEFAULT_GCODE_BUFFER_SIZE 1000 #define DEFAULT_G90_G91_INFLUENCES_EXTRUDER false class arc_welder { diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp index f1cc66d..5f8701f 100644 --- a/ArcWelder/segmented_arc.cpp +++ b/ArcWelder/segmented_arc.cpp @@ -155,11 +155,18 @@ bool segmented_arc::try_add_point(point p, double e_relative) { // If we haven't added a point, and we have exactly min_segments_, // pull off the initial arc point and try again + point old_initial_point = points_.pop_front(); // We have to remove the distance and e relative value // accumulated between the old arc start point and the new point new_initial_point = points_[0]; - original_shape_length_ -= utilities::get_cartesian_distance(old_initial_point.x, old_initial_point.y, new_initial_point.x, new_initial_point.y); + if (allow_z_axis_changes_) { + original_shape_length_ -= utilities::get_cartesian_distance(old_initial_point.x, old_initial_point.y, old_initial_point.z, new_initial_point.x, new_initial_point.y, new_initial_point.z); + } + else { + original_shape_length_ -= utilities::get_cartesian_distance(old_initial_point.x, old_initial_point.y, new_initial_point.x, new_initial_point.y); + } + e_relative_ -= new_initial_point.e_relative; //std::cout << " failed - removing start point and retrying current point.\n"; return try_add_point(p, e_relative); diff --git a/ArcWelder/segmented_arc.h b/ArcWelder/segmented_arc.h index 5bbdf34..9af5f25 100644 --- a/ArcWelder/segmented_arc.h +++ b/ArcWelder/segmented_arc.h @@ -28,7 +28,7 @@ #include #include -#define GCODE_CHAR_BUFFER_SIZE 100 +#define GCODE_CHAR_BUFFER_SIZE 1000 class segmented_arc : public segmented_shape diff --git a/ArcWelder/segmented_shape.cpp b/ArcWelder/segmented_shape.cpp index 170b1df..77448c0 100644 --- a/ArcWelder/segmented_shape.cpp +++ b/ArcWelder/segmented_shape.cpp @@ -381,6 +381,15 @@ bool arc::try_create_arc( // but also could indicate that our vector calculation above // got the direction wrong double arc_length = c.radius * angle_radians; + + if (allow_z_axis_changes) + { + // We may be traveling in 3 space, calculate the arc_length of the spiral + if (start_point.z != end_point.z) + { + arc_length = std::hypot(arc_length, end_point.z - start_point.z); + } + } // Calculate the percent difference of the original path double difference = (arc_length - approximate_length) / approximate_length; if (!utilities::is_zero(difference, path_tolerance_percent)) @@ -395,6 +404,14 @@ bool arc::try_create_arc( double test_radians = std::abs(angle_radians - 2 * PI_DOUBLE); // Calculate the length of that arc double test_arc_length = c.radius * test_radians; + if (allow_z_axis_changes) + { + // We may be traveling in 3 space, calculate the arc_length of the spiral + if (start_point.z != end_point.z) + { + test_arc_length = std::hypot(arc_length, end_point.z - start_point.z); + } + } difference = (test_arc_length - approximate_length) / approximate_length; if (!utilities::is_zero(difference, path_tolerance_percent)) { @@ -408,7 +425,7 @@ bool arc::try_create_arc( if (allow_z_axis_changes) { // Ensure the perimeter of the arc is less than that of a full circle - double perimeter = c.radius * 2.0 * PI_DOUBLE; + double perimeter = std::hypot(c.radius * 2.0 * PI_DOUBLE, end_point.z - start_point.z); if (perimeter <= approximate_length) { return false; } diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h index ac9b1db..3c8da0f 100644 --- a/ArcWelder/segmented_shape.h +++ b/ArcWelder/segmented_shape.h @@ -25,7 +25,7 @@ #pragma once #include #include -#define PI_DOUBLE 3.14159265358979323846 +#define PI_DOUBLE 3.14159265358979323846264338327950288 #include #include "utilities.h" @@ -121,7 +121,7 @@ struct circle { }; #define DEFAULT_RESOLUTION_MM 0.05 -#define DEFAULT_ALLOW_Z_AXIS_CHANGES true +#define DEFAULT_ALLOW_Z_AXIS_CHANGES false struct arc : circle { arc() { diff --git a/ArcWelderConsole/ArcWelderConsole.cpp b/ArcWelderConsole/ArcWelderConsole.cpp index 13e789e..ce17764 100644 --- a/ArcWelderConsole/ArcWelderConsole.cpp +++ b/ArcWelderConsole/ArcWelderConsole.cpp @@ -94,7 +94,13 @@ int main(int argc, char* argv[]) arg_description_stream.clear(); arg_description_stream.str(""); arg_description_stream << "If supplied, G90/G91 influences the extruder axis. Default Value: " << DEFAULT_G90_G91_INFLUENCES_EXTRUDER; - TCLAP::SwitchArg g90_arg("g", "g90-influences-extruder", arg_description_stream.str(), false); + TCLAP::SwitchArg g90_arg("g", "g90-influences-extruder", arg_description_stream.str(), DEFAULT_G90_G91_INFLUENCES_EXTRUDER); + + // -z --allow-z-axis-changes + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "(experimental) - If supplied, z-axis changes will be allowed within arcs (supports spiral vase mode). Default Value: " << DEFAULT_ALLOW_Z_AXIS_CHANGES; + TCLAP::SwitchArg allow_z_axis_changes_arg("z", "allow-z-axis-changes", arg_description_stream.str(), DEFAULT_ALLOW_Z_AXIS_CHANGES); // -g --hide-progress TCLAP::SwitchArg hide_progress_arg("p", "hide-progress", "If supplied, prevents progress updates from being displayed.", false); @@ -121,6 +127,7 @@ int main(int argc, char* argv[]) cmd.add(resolution_arg); cmd.add(path_tolerance_percent_arg); cmd.add(max_radius_arg); + cmd.add(allow_z_axis_changes_arg); cmd.add(g90_arg); cmd.add(hide_progress_arg); cmd.add(log_level_arg); @@ -140,6 +147,7 @@ int main(int argc, char* argv[]) resolution_mm = resolution_arg.getValue(); max_radius_mm = max_radius_arg.getValue(); path_tolerance_percent = path_tolerance_percent_arg.getValue(); + allow_z_axis_changes = allow_z_axis_changes_arg.getValue(); g90_g91_influences_extruder = g90_arg.getValue(); hide_progress = hide_progress_arg.getValue(); @@ -249,6 +257,7 @@ int main(int argc, char* argv[]) 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 << "\tAllow Z-Axis Changes : " << (allow_z_axis_changes ? "True" : "False") << "\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"); diff --git a/ArcWelderTest/ArcWelderTest.cpp b/ArcWelderTest/ArcWelderTest.cpp index abd51c7..226e4b6 100644 --- a/ArcWelderTest/ArcWelderTest.cpp +++ b/ArcWelderTest/ArcWelderTest.cpp @@ -241,14 +241,19 @@ static void TestAntiStutter(std::string filePath) std::vector logger_names; logger_names.push_back("arc_welder.gcode_conversion"); std::vector logger_levels; - //logger_levels.push_back(log_levels::DEBUG); + logger_levels.push_back(log_levels::NOSET); + logger_levels.push_back(log_levels::VERBOSE); + logger_levels.push_back(log_levels::DEBUG); logger_levels.push_back(log_levels::INFO); + logger_levels.push_back(log_levels::WARNING); + logger_levels.push_back(log_levels::ERROR); + logger_levels.push_back(log_levels::CRITICAL); logger* p_logger = new logger(logger_names, logger_levels); p_logger->set_log_level(INFO); //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( - SPIRAL_VASE_TEST_CYLINDER, + SPIRAL_VASE_TEST_DOUBLE_SPIRAL, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, diff --git a/ArcWelderTest/ArcWelderTest.h b/ArcWelderTest/ArcWelderTest.h index 6345761..90ed99a 100644 --- a/ArcWelderTest/ArcWelderTest.h +++ b/ArcWelderTest/ArcWelderTest.h @@ -83,6 +83,8 @@ static std::string SPIRAL_TEST = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStu 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"; +static std::string SPIRAL_VASE_TEST_SINGLE_LAYER_CYLINDER = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\SpiralVaseTest\\SpiralVaseSingleLayer_Cylinder.gcode"; +static std::string SPIRAL_VASE_TEST_PI_BOWL = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\SpiralVaseTest\\SpiralVaseTest_PiBowl.gcode"; diff --git a/GcodeProcessorLib/logger.cpp b/GcodeProcessorLib/logger.cpp index 8511777..9fa5a6d 100644 --- a/GcodeProcessorLib/logger.cpp +++ b/GcodeProcessorLib/logger.cpp @@ -30,13 +30,14 @@ logger::logger(std::vector names, std::vector levels) { logger_names_ = new std::string[static_cast(num_loggers_)]; logger_levels_ = new int[static_cast(num_loggers_)]; // this is slow due to the vectors, but it is trivial. Could switch to an iterator + for (int index = 0; index < num_loggers_; index++) { logger_names_[index] = names[index]; logger_levels_[index] = levels[index]; } - set_log_level_by_value(NOSET); + } logger::~logger() { diff --git a/PyArcWelder/py_arc_welder.h b/PyArcWelder/py_arc_welder.h index 4d0e56b..ba2dcf7 100644 --- a/PyArcWelder/py_arc_welder.h +++ b/PyArcWelder/py_arc_welder.h @@ -42,7 +42,8 @@ public: double resolution_mm, double path_tolerance_percent, double max_radius, - bool g90_g91_influences_extruder, + bool g90_g91_influences_extruder, + bool allow_z_axis_changes, int buffer_size, PyObject* py_progress_callback ): arc_welder( @@ -52,7 +53,8 @@ public: resolution_mm, path_tolerance_percent, max_radius, - g90_g91_influences_extruder, + g90_g91_influences_extruder, + allow_z_axis_changes, buffer_size ){ guid_ = guid; diff --git a/PyArcWelder/py_arc_welder_extension.cpp b/PyArcWelder/py_arc_welder_extension.cpp index bce6620..194ee22 100644 --- a/PyArcWelder/py_arc_welder_extension.cpp +++ b/PyArcWelder/py_arc_welder_extension.cpp @@ -148,7 +148,13 @@ extern "C" void initPyArcWelder(void) std::vector logger_names; logger_names.push_back("arc_welder.gcode_conversion"); std::vector logger_levels; + logger_levels.push_back(log_levels::NOSET); + logger_levels.push_back(log_levels::VERBOSE); logger_levels.push_back(log_levels::DEBUG); + logger_levels.push_back(log_levels::INFO); + logger_levels.push_back(log_levels::WARNING); + logger_levels.push_back(log_levels::ERROR); + logger_levels.push_back(log_levels::CRITICAL); p_py_logger = new py_logger(logger_names, logger_levels); p_py_logger->initialize_loggers(); std::string message = "PyArcWelder V0.1.0rc1.dev2 imported - Copyright (C) 2019 Brad Hochgesang..."; @@ -190,7 +196,7 @@ 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.g90_g91_influences_extruder, DEFAULT_GCODE_BUFFER_SIZE, py_progress_callback); + 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.g90_g91_influences_extruder, args.allow_z_axis_changes, DEFAULT_GCODE_BUFFER_SIZE, py_progress_callback); 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); @@ -294,6 +300,17 @@ static bool ParseArgs(PyObject* py_args, py_gcode_arc_args& args, PyObject** py_ 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 Allow Z Axis Changes + // allow_z_axis_changes + PyObject* py_allow_z_axis_changes = PyDict_GetItemString(py_args, "allow_z_axis_changes"); + if (py_allow_z_axis_changes == NULL) + { + std::string message = "ParseArgs - Unable to retrieve allow_z_axis_changes from the args."; + p_py_logger->log_exception(GCODE_CONVERSION, message); + return false; + } + args.allow_z_axis_changes = PyLong_AsLong(py_allow_z_axis_changes) > 0; + // Extract G90/G91 influences extruder // g90_influences_extruder PyObject* py_g90_g91_influences_extruder = PyDict_GetItemString(py_args, "g90_g91_influences_extruder"); diff --git a/PyArcWelder/py_arc_welder_extension.h b/PyArcWelder/py_arc_welder_extension.h index f288c9a..fb5524c 100644 --- a/PyArcWelder/py_arc_welder_extension.h +++ b/PyArcWelder/py_arc_welder_extension.h @@ -50,6 +50,7 @@ struct py_gcode_arc_args { path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT; max_radius_mm = DEFAULT_MAX_RADIUS_MM; g90_g91_influences_extruder = DEFAULT_G90_G91_INFLUENCES_EXTREUDER; + allow_z_axis_changes = DEFAULT_ALLOW_Z_AXIS_CHANGES; log_level = 0; } py_gcode_arc_args( @@ -60,6 +61,7 @@ struct py_gcode_arc_args { double path_tolerance_percent_, double max_radius_mm_, bool g90_g91_influences_extruder_, + bool allow_z_axis_changes_, int log_level_ ) { guid = guid_; @@ -68,6 +70,7 @@ struct py_gcode_arc_args { resolution_mm = resolution_mm_; path_tolerance_percent = path_tolerance_percent_; max_radius_mm = max_radius_mm_; + allow_z_axis_changes = allow_z_axis_changes_; g90_g91_influences_extruder = g90_g91_influences_extruder_; log_level = log_level_; } @@ -76,6 +79,7 @@ struct py_gcode_arc_args { std::string target_path; double resolution_mm; double path_tolerance_percent; + bool allow_z_axis_changes; bool g90_g91_influences_extruder; double max_radius_mm; int log_level; -- cgit v1.2.3