From 9d1d644013ea74e89ac81f42006b115474cf955e Mon Sep 17 00:00:00 2001 From: FormerLurker Date: Thu, 25 Nov 2021 13:36:18 -0600 Subject: Clean up error correction and debug parameters for the console applications. Update readme.md. --- ArcWelder/arc_welder.cpp | 7 +- ArcWelder/arc_welder.h | 26 +- ArcWelderConsole/ArcWelderConsole.cpp | 398 ++++++++--------- ArcWelderConsole/ArcWelderConsole.vcxproj | 3 + .../ArcWelderInverseProcessor.cpp | 486 ++++++++++++--------- .../ArcWelderInverseProcessor.h | 3 +- .../ArcWelderInverseProcessor.vcxproj | 3 + ArcWelderInverseProcessor/arc_interpolation.cpp | 6 +- ArcWelderInverseProcessor/arc_interpolation.h | 2 +- ArcWelderInverseProcessor/firmware.cpp | 33 +- ArcWelderInverseProcessor/firmware.h | 302 +++++++++---- ArcWelderInverseProcessor/marlin_1.cpp | 9 +- ArcWelderInverseProcessor/marlin_2.cpp | 25 +- ArcWelderInverseProcessor/prusa.cpp | 36 +- ArcWelderInverseProcessor/prusa.h | 16 - ArcWelderInverseProcessor/repetier.cpp | 18 +- ArcWelderInverseProcessor/smoothieware.cpp | 3 +- GcodeProcessorLib/fpconv.h | 3 + GcodeProcessorLib/utilities.cpp | 26 +- GcodeProcessorLib/utilities.h | 4 +- TCLAP/TCLAP.vcxproj | 1 + TCLAP/TCLAP.vcxproj.filters | 3 + TCLAP/tclap/tclap_version.h | 3 + readme.md | 133 ++++-- 24 files changed, 923 insertions(+), 626 deletions(-) create mode 100644 TCLAP/tclap/tclap_version.h diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp index 2103763..e9a9ddd 100644 --- a/ArcWelder/arc_welder.cpp +++ b/ArcWelder/arc_welder.cpp @@ -981,8 +981,11 @@ void arc_welder::add_arcwelder_comment_to_target() } stream << "; default_xyz_precision=" << std::setprecision(0) << static_cast(current_arc_.get_xyz_precision()) << "\n"; stream << "; default_e_precision=" << std::setprecision(0) << static_cast(current_arc_.get_e_precision()) << "\n"; - stream << "; extrusion_rate_variance_percent=" << std::setprecision(1) << (extrusion_rate_variance_percent_ * 100.0) << "%\n\n"; - + if (extrusion_rate_variance_percent_ > 0) + { + stream << "; extrusion_rate_variance=" << std::setprecision(1) << (extrusion_rate_variance_percent_ * 100.0) << "%\n"; + } + stream << "\n"; output_file_ << stream.str(); } diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h index ec07e7d..7535bf0 100644 --- a/ArcWelder/arc_welder.h +++ b/ArcWelder/arc_welder.h @@ -44,6 +44,8 @@ #define _CRT_SECURE_NO_WARNINGS #endif +#define ARC_WELDER_INFO_STRING "Arc Welder: Anti-Stutter\nConverts G0/G1 commands to G2/G3 (arc) commands. Reduces the number of gcodes per second sent to a 3D printer, which can reduce stuttering."; + static const int segment_statistic_lengths_count = 12; const double segment_statistic_lengths[] = { 0.002f, 0.005f, 0.01f, 0.05f, 0.1f, 0.5f, 1.0f, 5.0f, 10.0f, 20.0f, 50.0f, 100.0f }; @@ -623,15 +625,31 @@ struct arc_welder_args } stream << "\tResolution : " << resolution_mm << "mm (+-" << std::setprecision(5) << resolution_mm / 2.0 << "mm)\n"; stream << "\tPath Tolerance : " << std::setprecision(3) << path_tolerance_percent * 100.0 << "%\n"; - stream << "\tMaximum Arc Radius : " << std::setprecision(0) << max_radius_mm << "mm\n"; - stream << "\tMin Arc Segments : " << std::setprecision(0) << min_arc_segments << "\n"; - stream << "\tMM Per Arc Segment : " << std::setprecision(3) << mm_per_arc_segment << "\n"; + stream << "\tMaximum Arc Radius : " << std::setprecision(1) << max_radius_mm << "mm\n"; + bool firmware_compensation_enabled = min_arc_segments > 0 && mm_per_arc_segment > 0.0; + stream << "\tFirmware Compensation : " << (firmware_compensation_enabled ? "True" : "False") << "\n"; + if (firmware_compensation_enabled) + { + stream << "\tMin Arc Segments : " << std::setprecision(0) << min_arc_segments << "\n"; + stream << "\tMM Per Arc Segment : " << std::setprecision(3) << mm_per_arc_segment << "\n"; + } + stream << "\tAllow 3D Arcs : " << (allow_3d_arcs ? "True" : "False") << "\n"; stream << "\tAllow Travel Arcs : " << (allow_travel_arcs ? "True" : "False") << "\n"; stream << "\tAllow Dynamic Precision : " << (allow_dynamic_precision ? "True" : "False") << "\n"; stream << "\tDefault XYZ Precision : " << std::setprecision(0) << static_cast(default_xyz_precision) << "\n"; stream << "\tDefault E Precision : " << std::setprecision(0) << static_cast(default_e_precision) << "\n"; - stream << "\tExtrusion Rate Variance % : " << std::setprecision(3) << extrusion_rate_variance_percent * 100.0 << "%\n"; + stream << "\tExtrusion Rate Variance : "; + if (extrusion_rate_variance_percent == 0) + { + stream << "Unlimited"; + } + else + { + stream << extrusion_rate_variance_percent * 100.0 << "%"; + } + stream << "\n"; + stream << "\tG90/G91 Influences Extruder : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; if (max_gcode_length == 0) { diff --git a/ArcWelderConsole/ArcWelderConsole.cpp b/ArcWelderConsole/ArcWelderConsole.cpp index a9245ad..dbc6085 100644 --- a/ArcWelderConsole/ArcWelderConsole.cpp +++ b/ArcWelderConsole/ArcWelderConsole.cpp @@ -32,6 +32,7 @@ #include #include "gcode_position.h" #include +#include #define DEFAULT_ARG_DOUBLE_PRECISION 4 #define PROGRESS_TYPE_NONE "NONE" @@ -44,161 +45,157 @@ int main(int argc, char* argv[]) std::string log_level_string; std::string log_level_string_default = "INFO"; std::string progress_type; - std::string progress_type_default_string = PROGRESS_TYPE_SIMPLE; int log_level_value; bool hide_progress = false; - // Add info about the application - std::string info = "Arc Welder: Anti-Stutter - Reduces the number of gcodes per second sent to a 3D printer that supports arc commands (G2 G3)."; + // Add info about the application + std::string info = "Arc Welder: Anti-Stutter\nConverts G0/G1 commands to G2/G3 (arc) commands. Reduces the number of gcodes per second sent to a 3D printer, which can reduce stuttering."; // Add the current vesion information info.append("\nVersion: ").append(GIT_TAGGED_VERSION); info.append(", Branch: ").append(GIT_BRANCH); info.append(", BuildDate: ").append(BUILD_DATE); info.append("\n").append("Copyright(C) ").append(COPYRIGHT_DATE).append(" - ").append(AUTHOR); - info.append("\n").append("An algorithm for producing fast floating point strings, fpconv, was added with the following notice: Copyright (C) 2014 Milo Yip"); - info.append("\n").append("The original fpconv algorithm provides the following notice: Copyright(c) 2013 Andreas Samoljuk"); + info.append("\n").append("Includes source code derived from fpconv. ").append(FPCONV_COPYRIGHT_STRING); + info.append("\n").append("Includes TCLAP v").append(TCLAP_VERSION_STRING).append(". ").append(TCLAP_COPYRIGHT_STRING); std::stringstream arg_description_stream; arg_description_stream << std::fixed << std::setprecision(5); - // Extract arguments - try { - // Define the command line object - TCLAP::CmdLine cmd(info, '=', GIT_TAGGED_VERSION); - - // Define Arguments - + // Define the command line object + TCLAP::CmdLine cmd(info, '=', GIT_TAGGED_VERSION); + // Define Arguments // - TCLAP::UnlabeledValueArg source_arg("source", "The source gcode file to convert.", true, "", "path to source gcode file"); - - // - TCLAP::UnlabeledValueArg target_arg("target", "The target gcode file containing the converted code. If this is not supplied, the source path will be used and the source file will be overwritten.", false, "", "path to target gcode file"); - - // -g --g90-influences-extruder - 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(), DEFAULT_G90_G91_INFLUENCES_EXTRUDER); - - // -r --resolution-mm - arg_description_stream << "The resolution in mm of the of the output. Determines the maximum tool path deviation allowed during conversion. Default Value: " << DEFAULT_RESOLUTION_MM; - TCLAP::ValueArg resolution_arg("r", "resolution-mm", arg_description_stream.str(), false, DEFAULT_RESOLUTION_MM, "float"); - - // -t --path-tolerance-percent - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "This is the maximum allowable difference between the arc path and the original toolpath."; - arg_description_stream << " Expressed as a decimal percent, where 0.05 = 5.0%. The lower this value is, the more arcs will be aborted, but values over 0.25 (25%) are not recommended, as they could negatively impact print quality. Default Value: " << ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT << " (" << ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT * 100 << "%)"; - TCLAP::ValueArg path_tolerance_percent_arg("t", "path-tolerance-percent", arg_description_stream.str(), false, DEFAULT_RESOLUTION_MM, "float"); - - // -m --max-radius-mm - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The maximum radius of any arc in mm. Default Value: " << DEFAULT_MAX_RADIUS_MM; - TCLAP::ValueArg max_radius_arg("m", "max-radius-mm", arg_description_stream.str(), false, DEFAULT_MAX_RADIUS_MM, "float"); - - // -z --allow-3d-arcs - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "(experimental) - If supplied, 3D arcs will be allowed (supports spiral vase mode). Not all firmware supports this. Default Value: " << DEFAULT_ALLOW_3D_ARCS; - TCLAP::SwitchArg allow_3d_arcs_arg("z", "allow-3d-arcs", arg_description_stream.str(), DEFAULT_ALLOW_3D_ARCS); - - // -y --allow-travel-arcs - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "(experimental) - If supplied, travel arcs will be allowed. Default Value: " << DEFAULT_ALLOW_TRAVEL_ARCS; - TCLAP::SwitchArg allow_travel_arcs_arg("y", "allow-travel-arcs", arg_description_stream.str(), DEFAULT_ALLOW_TRAVEL_ARCS); - - // -d --allow-dynamic-precision - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "If supplied, arcwelder will adjust the precision of the outputted gcode based on the precision of the input gcode. Default Value: " << DEFAULT_ALLOW_DYNAMIC_PRECISION; - TCLAP::SwitchArg allow_dynamic_precision_arg("d", "allow-dynamic-precision", arg_description_stream.str(), DEFAULT_ALLOW_DYNAMIC_PRECISION); - - // -x --default-xyz-precision - 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 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 default_e_precision_arg("e", "default-e-precision", arg_description_stream.str(), false, DEFAULT_E_PRECISION, "unsigned int"); - - // -s --mm-per-arc-segment - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The mm per arc segment as defined in your firmware. Used to compensate for firmware without min-arc-segments setting. Requires that min-arc-segments be set. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; - TCLAP::ValueArg mm_per_arc_segment_arg("s", "mm-per-arc-segment", arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); - - // -a --min-arc-segments - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The minimum number of segments in a full circle of the same radius as any given arc. Can only be used if --mm-per-arc-segment is also set. Used to compensate for firmware without min-arc-segments setting. Default: " << DEFAULT_MIN_ARC_SEGMENTS; - TCLAP::ValueArg min_arc_segments_arg("a", "min-arc-segments", arg_description_stream.str(), false, DEFAULT_MIN_ARC_SEGMENTS, "int"); - - // -v --extrusion-rate-variance - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "(experimental) - The allowed variance in extrusion rate by percent, where 0.05 = 5.0%. A value of 0 will disable this feature. Default Value: " << DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT << " (" << DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT * 100 << "%)"; - TCLAP::ValueArg extrusion_rate_variance_percent_arg("v", "extrusion-rate-variance-percent", arg_description_stream.str(), false, DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT, "double"); - - // -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 max_gcode_length_arg("c", "max-gcode-length", arg_description_stream.str(), false, DEFAULT_MAX_GCODE_LENGTH, "int"); - - // -p --progress-type - std::vector progress_type_vector; - std::string progress_type_default_string = PROGRESS_TYPE_SIMPLE; - progress_type_vector.push_back(PROGRESS_TYPE_NONE); - progress_type_vector.push_back(PROGRESS_TYPE_SIMPLE); - progress_type_vector.push_back(PROGRESS_TYPE_FULL); - TCLAP::ValuesConstraint progress_type_constraint(progress_type_vector); - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "Sets the progress type display. Default Value " << progress_type_default_string; - TCLAP::ValueArg progress_type_arg("p", "progress-type", arg_description_stream.str(), false, progress_type_default_string, &progress_type_constraint); - - // -l --log-level - std::vector log_levels_vector; - log_levels_vector.push_back("NOSET"); - log_levels_vector.push_back("VERBOSE"); - log_levels_vector.push_back("DEBUG"); - log_levels_vector.push_back("INFO"); - log_levels_vector.push_back("WARNING"); - log_levels_vector.push_back("ERROR"); - log_levels_vector.push_back("CRITICAL"); - log_levels_vector.push_back(""); - TCLAP::ValuesConstraint log_levels_constraint(log_levels_vector); - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "Sets console log level. Default Value: " << log_level_string_default; - TCLAP::ValueArg log_level_arg("l", "log-level", arg_description_stream.str(), false, log_level_string_default, &log_levels_constraint); + TCLAP::UnlabeledValueArg source_arg("source", "The source gcode file to convert.", true, "", "path to source gcode file"); + + // + TCLAP::UnlabeledValueArg target_arg("target", "The target gcode file containing the converted code. If this is not supplied, the source path will be used and the source file will be overwritten.", false, "", "path to target gcode file"); + + // -g --g90-influences-extruder + 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(), DEFAULT_G90_G91_INFLUENCES_EXTRUDER); + + // -r --resolution-mm + arg_description_stream << "The resolution in mm of the of the output. Determines the maximum tool path deviation allowed during conversion. Restrictions: Only values greater than 0 are allowed. Default Value: " << DEFAULT_RESOLUTION_MM; + TCLAP::ValueArg resolution_arg("r", "resolution-mm", arg_description_stream.str(), false, DEFAULT_RESOLUTION_MM, "float"); + + // -t --path-tolerance-percent + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "This is the maximum allowable difference between the arc path and the original toolpath."; + arg_description_stream << " Expressed as a decimal percent, where 0.05 = 5.0%. The lower this value is, the more arcs will be aborted, but values over 0.25 (25%) are not recommended, as they could negatively impact print quality. Restrictions: Only values greater than 0 (0%) and less than 1.0 (100%) are allowed. Default Value: " << ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT << " (" << ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT * 100 << "%)"; + TCLAP::ValueArg path_tolerance_percent_arg("t", "path-tolerance-percent", arg_description_stream.str(), false, DEFAULT_RESOLUTION_MM, "float"); + + // -m --max-radius-mm + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The maximum radius of any arc in mm. Restrictions: Only values greater than 0.0 are allowed. Default Value: " << DEFAULT_MAX_RADIUS_MM; + TCLAP::ValueArg max_radius_arg("m", "max-radius-mm", arg_description_stream.str(), false, DEFAULT_MAX_RADIUS_MM, "float"); + + // -z --allow-3d-arcs + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "(experimental) - If supplied, 3D arcs will be allowed (supports spiral vase mode). Not all firmware supports this. Default Value: " << DEFAULT_ALLOW_3D_ARCS; + TCLAP::SwitchArg allow_3d_arcs_arg("z", "allow-3d-arcs", arg_description_stream.str(), DEFAULT_ALLOW_3D_ARCS); + + // -y --allow-travel-arcs + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "(experimental) - If supplied, travel arcs will be allowed. Default Value: " << DEFAULT_ALLOW_TRAVEL_ARCS; + TCLAP::SwitchArg allow_travel_arcs_arg("y", "allow-travel-arcs", arg_description_stream.str(), DEFAULT_ALLOW_TRAVEL_ARCS); + + // -d --allow-dynamic-precision + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "If supplied, arcwelder will adjust the precision of the outputted gcode based on the precision of the input gcode. Default Value: " << DEFAULT_ALLOW_DYNAMIC_PRECISION; + TCLAP::SwitchArg allow_dynamic_precision_arg("d", "allow-dynamic-precision", arg_description_stream.str(), DEFAULT_ALLOW_DYNAMIC_PRECISION); + + // -x --default-xyz-precision + 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. Restrictions: Allowed values are 3, 4, 5, or 6. Default Value: " << DEFAULT_XYZ_PRECISION; + TCLAP::ValueArg 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. Restrictions: Allowed values are 3, 4, 5, or 6. Default Value: " << DEFAULT_E_PRECISION; + TCLAP::ValueArg default_e_precision_arg("e", "default-e-precision", arg_description_stream.str(), false, DEFAULT_E_PRECISION, "unsigned int"); + + // -s --mm-per-arc-segment + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The mm per arc segment as defined in your firmware. Used to compensate for firmware without min-arc-segments setting. Restrictions: Only values greater than or equal to 0.0 are allowed. If set greater than 0, min-arc-segments must also be set. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; + TCLAP::ValueArg mm_per_arc_segment_arg("s", "mm-per-arc-segment", arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); + + // -a --min-arc-segments + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum number of segments in a full circle of the same radius as any given arc. Used to compensate for firmware without min-arc-segments setting. Restrictions: Only values greater than or equal to 0.0 are allowed. If set greater than 0, mm-per-arc-segment must also be set. Default Value: " << DEFAULT_MIN_ARC_SEGMENTS; + TCLAP::ValueArg min_arc_segments_arg("a", "min-arc-segments", arg_description_stream.str(), false, DEFAULT_MIN_ARC_SEGMENTS, "int"); + + // -v --extrusion-rate-variance + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "(experimental) - The allowed variance in extrusion rate by percent, where 0.05 = 5.0%. A value of 0 will disable this feature. Restrictions: Only values greater than or equal to 0.0 are allowed. Default Value: " << DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT << " (" << DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT * 100 << "%)"; + TCLAP::ValueArg extrusion_rate_variance_percent_arg("v", "extrusion-rate-variance-percent", arg_description_stream.str(), false, DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT, "double"); + + // -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. Restrictions: Can be set to 0, or values > 30. Default Value: " << DEFAULT_MAX_GCODE_LENGTH; + TCLAP::ValueArg max_gcode_length_arg("c", "max-gcode-length", arg_description_stream.str(), false, DEFAULT_MAX_GCODE_LENGTH, "int"); + + // -p --progress-type + std::vector progress_type_vector; + std::string progress_type_default_string = PROGRESS_TYPE_SIMPLE; + progress_type_vector.push_back(PROGRESS_TYPE_NONE); + progress_type_vector.push_back(PROGRESS_TYPE_SIMPLE); + progress_type_vector.push_back(PROGRESS_TYPE_FULL); + TCLAP::ValuesConstraint progress_type_constraint(progress_type_vector); + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Sets the progress type display. Default Value " << progress_type_default_string; + TCLAP::ValueArg progress_type_arg("p", "progress-type", arg_description_stream.str(), false, progress_type_default_string, &progress_type_constraint); + + // -l --log-level + std::vector log_levels_vector; + log_levels_vector.push_back("NOSET"); + log_levels_vector.push_back("VERBOSE"); + log_levels_vector.push_back("DEBUG"); + log_levels_vector.push_back("INFO"); + log_levels_vector.push_back("WARNING"); + log_levels_vector.push_back("ERROR"); + log_levels_vector.push_back("CRITICAL"); + TCLAP::ValuesConstraint log_levels_constraint(log_levels_vector); + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Sets console log level. Default Value: " << log_level_string_default; + TCLAP::ValueArg 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); + cmd.add(resolution_arg); + cmd.add(path_tolerance_percent_arg); + cmd.add(max_radius_arg); + cmd.add(min_arc_segments_arg); + cmd.add(mm_per_arc_segment_arg); + cmd.add(allow_3d_arcs_arg); + cmd.add(allow_travel_arcs_arg); + cmd.add(allow_dynamic_precision_arg); + cmd.add(default_xyz_precision_arg); + cmd.add(default_e_precision_arg); + cmd.add(extrusion_rate_variance_percent_arg); + cmd.add(max_gcode_length_arg); + cmd.add(g90_arg); + cmd.add(progress_type_arg); + cmd.add(log_level_arg); + try { - // Add all arguments - cmd.add(source_arg); - cmd.add(target_arg); - cmd.add(resolution_arg); - cmd.add(path_tolerance_percent_arg); - cmd.add(max_radius_arg); - cmd.add(min_arc_segments_arg); - cmd.add(mm_per_arc_segment_arg); - cmd.add(allow_3d_arcs_arg); - cmd.add(allow_travel_arcs_arg); - cmd.add(allow_dynamic_precision_arg); - cmd.add(default_xyz_precision_arg); - cmd.add(default_e_precision_arg); - cmd.add(extrusion_rate_variance_percent_arg); - cmd.add(max_gcode_length_arg); - cmd.add(g90_arg); - cmd.add(progress_type_arg); - cmd.add(log_level_arg); - // Parse the argv array. cmd.parse(argc, argv); @@ -220,108 +217,114 @@ 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(); - unsigned int xyz_precision = default_xyz_precision_arg.getValue(); - unsigned int e_precision = default_e_precision_arg.getValue(); + args.default_xyz_precision = static_cast(default_xyz_precision_arg.getValue()); + args.default_e_precision = static_cast(default_e_precision_arg.getValue()); args.extrusion_rate_variance_percent = extrusion_rate_variance_percent_arg.getValue(); args.max_gcode_length = max_gcode_length_arg.getValue(); progress_type = progress_type_arg.getValue(); log_level_string = log_level_arg.getValue(); log_level_value = -1; + + // ensure the source file exists + if (!utilities::does_file_exist(args.source_path)) + { + throw TCLAP::ArgException("The source file does not exist at the specified path.", source_arg.getName(), "File does not exist error"); + } - // Check the entered values - bool has_error = false; if (args.resolution_mm <= 0) { - std::cerr << "error: The provided resolution of " << args.resolution_mm << " is negative, which is not allowed." < 1000000) + if (args.path_tolerance_percent >= 1.0) { - // warning - std::cout << "warning: The provided path max radius of " << args.max_radius_mm << "mm is greater than 1000000 (1km), which is not recommended." << std::endl; + throw TCLAP::ArgException("The provided value is greater than or equal to 1 (100%).", path_tolerance_percent_arg.toString()); } - if (args.min_arc_segments < 0) + if (args.mm_per_arc_segment < 0) { - // warning - std::cout << "warning: The provided min_arc_segments " << args.min_arc_segments << " is less than zero. Setting to 0." << std::endl; - args.min_arc_segments = 0; + throw TCLAP::ArgException("The provided value is negative.", mm_per_arc_segment_arg.toString()); } - if (args.mm_per_arc_segment < 0) + if (args.min_arc_segments < 0) { - // warning - std::cout << "warning: The provided mm_per_arc_segment " << args.mm_per_arc_segment << "mm is less than zero. Setting to 0." << std::endl; - args.mm_per_arc_segment = 0; + throw TCLAP::ArgException("The provided value is negative.", min_arc_segments_arg.toString()); } - if (args.path_tolerance_percent > 0.25) + if (args.mm_per_arc_segment != 0.0 && args.min_arc_segments == 0) { - // warning - std::cout << "warning: The provided path tolerance percent of " << args.path_tolerance_percent << " is greater than 0.25 (25%), which is not recommended." << std::endl; + throw TCLAP::ArgException("You must also specify a non zero value for the " + min_arc_segments_arg.toString() + " argument.", mm_per_arc_segment_arg.toString()); } - else if (args.path_tolerance_percent < 0.001 && args.path_tolerance_percent > 0) + else if (args.mm_per_arc_segment == 0.0 && args.min_arc_segments != 0) { - // warning - std::cout << "warning: The provided path tolerance percent of " << args.path_tolerance_percent << " is less than 0.001 (0.1%), which is not recommended, and will result in very few arcs being generated." << std::endl; + throw TCLAP::ArgException("You must also specify a non zero value for the " + mm_per_arc_segment_arg.toString() + " argument.", min_arc_segments_arg.toString()); } - if (xyz_precision < 3) + if (args.default_xyz_precision < 3) { - // warning - 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; + throw TCLAP::ArgException("The provided value is less than 3.", default_xyz_precision_arg.toString()); } - if (e_precision < DEFAULT_E_PRECISION) + if (args.default_e_precision < 3) { - // warning - 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; + throw TCLAP::ArgException("The provided value is less than 3.", default_e_precision_arg.toString()); } - if (xyz_precision > 6) + if (args.default_xyz_precision > 6) { - // warning - 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; + throw TCLAP::ArgException("The provided value is greater than 6.", default_xyz_precision_arg.toString()); } - if (e_precision > 6) + if (args.default_e_precision > 6) { - // warning - 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; + throw TCLAP::ArgException("The provided value is greater than 6.", default_e_precision_arg.toString()); } - - // 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 - std::cout << "warning: The provided extrusion_rate_variance_percent " << args.extrusion_rate_variance_percent << " is less than 0. Applying the default setting of " << DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT*100 << "%." << std::endl; - args.extrusion_rate_variance_percent = DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT; + throw TCLAP::ArgException("The provided value is negative.", extrusion_rate_variance_percent_arg.toString()); } 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 (no limit)." << std::endl; - args.max_gcode_length = DEFAULT_MAX_GCODE_LENGTH; + throw TCLAP::ArgException("The provided value is negative.", max_gcode_length_arg.toString()); + } + + if (args.max_gcode_length > 0 && args.max_gcode_length < 31) + { + throw TCLAP::ArgException("The provided value is greater than 0 and less than 31.", max_gcode_length_arg.toString()); + } + if (args.max_radius_mm <= 0) + { + throw TCLAP::ArgException("The provided value is less than or equal to 0.", max_radius_arg.toString()); + } + + if (args.extrusion_rate_variance_percent == 0) + { + // warning + std::cout << "warning: The provided path max radius of " << args.max_radius_mm << "mm is greater than 1000000 (1km), which is not recommended.\n"; } - if (has_error) + if (args.max_radius_mm > 1000000) + { + // warning + std::cout << "warning: The provided path max radius of " << args.max_radius_mm << "mm is greater than 1000000 (1km), which is not recommended.\n"; + } + + if (args.path_tolerance_percent > 0.25) + { + // warning + std::cout << "warning: The provided path tolerance percent of " << args.path_tolerance_percent << " is greater than 0.25 (25%), which is not recommended.\n"; + } + else if (args.path_tolerance_percent < 0.001 && args.path_tolerance_percent > 0) { - return 1; + // warning + std::cout << "warning: The provided path tolerance percent of " << args.path_tolerance_percent << " is less than 0.001 (0.1%), which is not recommended, and will result in very few arcs being generated.\n"; } for (unsigned int log_name_index = 0; log_name_index < log_level_names_size; log_name_index++) @@ -335,14 +338,15 @@ int main(int argc, char* argv[]) if (log_level_value == -1) { // TODO: Does this work? - throw new TCLAP::ArgException("Unknown log level"); + throw new TCLAP::ArgException("Unknown log level", log_level_arg.toString()); } } // catch argument exceptions catch (TCLAP::ArgException& e) { - std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; + // This will raise an exit exception + cmd.getOutput()->failure(cmd, e); return 1; } diff --git a/ArcWelderConsole/ArcWelderConsole.vcxproj b/ArcWelderConsole/ArcWelderConsole.vcxproj index 9bfc6c5..c7b54b2 100644 --- a/ArcWelderConsole/ArcWelderConsole.vcxproj +++ b/ArcWelderConsole/ArcWelderConsole.vcxproj @@ -106,10 +106,12 @@ true $(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\ + ArcWelder true $(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\ + ArcWelder false @@ -119,6 +121,7 @@ false $(SolutionDir)\GcodeProcessorLib\;$(SolutionDir)\ArcWelder\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\ + ArcWelder diff --git a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp index f3d35c3..9a82f76 100644 --- a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp +++ b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp @@ -46,7 +46,13 @@ #include "version.h" #include "utilities.h" #include +#include #define DEFAULT_ARG_DOUBLE_PRECISION 4 +#define COMMAND_LINE_ARGUMENT_SEPARATOR "," +#define COMMAND_LINE_ARGUMENT_PREFIX "--" +#define COMMAND_LINE_ARGUMENT_PREFIX_SHORT "-" +#define COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING "_" +#define COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE "-" int main(int argc, char* argv[]) { try { @@ -59,13 +65,13 @@ int main(int argc, char* argv[]) } int run_arc_straightener(int argc, char* argv[]) { - std::string info = "Arc Straightener - Converts G2/G3 commands to G1/G2 commands.."; + std::string info = "Arc Straightener\nConverts G2/G3 commands to G1/G2 commands.."; info.append("\nVersion: ").append(GIT_TAGGED_VERSION); info.append(", Branch: ").append(GIT_BRANCH); info.append(", BuildDate: ").append(BUILD_DATE); info.append("\n").append("Copyright(C) ").append(COPYRIGHT_DATE).append(" - ").append(AUTHOR); - + info.append("\n").append("Includes TCLAP v").append(TCLAP_VERSION_STRING).append(". ").append(TCLAP_COPYRIGHT_STRING); std::stringstream arg_description_stream; arg_description_stream << std::fixed << std::setprecision(5); @@ -82,196 +88,252 @@ int run_arc_straightener(int argc, char* argv[]) repetier repetier_firmware(args.firmware_args); prusa prusa_firmware(args.firmware_args); smoothieware smoothieware_firmware(args.firmware_args); - - // Extract arguments - try { - // Define the command line object - TCLAP::CmdLine cmd(info, '=', GIT_TAGGED_VERSION); - // Define a special command line object for various help requests - TCLAP::CmdLine help_cmd(info, '=', GIT_TAGGED_VERSION, false); + + // Define the command line object + TCLAP::CmdLine cmd(info, '=', GIT_TAGGED_VERSION); + // Define a special command line object for various help requests + TCLAP::CmdLine help_cmd(info, '=', GIT_TAGGED_VERSION, false); - // - TCLAP::UnlabeledValueArg source_arg("source", "The source gcode file to convert.", true, "", "path to source gcode file"); + // + TCLAP::UnlabeledValueArg source_arg("source", "The source gcode file to convert.", true, "", "path to source gcode file"); - // - TCLAP::UnlabeledValueArg target_arg("target", "The target gcode file containing the converted code. If this is not supplied, the source path will be used and the source file will be overwritten.", false, "", "path to target gcode file"); + // + TCLAP::UnlabeledValueArg target_arg("target", "The target gcode file containing the converted code. If this is not supplied, the source path will be used and the source file will be overwritten.", false, "", "path to target gcode file"); - // -f --firmware-type - std::vector firmware_types_vector; - for (int i = 0; i < NUM_FIRMWARE_TYPES; i++) - { + // -f --firmware-type + std::vector firmware_types_vector; + for (int i = 0; i < NUM_FIRMWARE_TYPES; i++) + { firmware_types_vector.push_back(firmware_type_names[i]); - } - TCLAP::ValuesConstraint firmware_type_constraint(firmware_types_vector); - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "Sets the firmware to emulate. Default Value: " << firmware_type_names[DEFAULT_FIRMWARE_TYPE]; - TCLAP::ValueArg firmware_type_arg("f", "firmware-type", arg_description_stream.str(), false, firmware_type_names[DEFAULT_FIRMWARE_TYPE], &firmware_type_constraint); - - // -v --firmware-version - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "Sets the firmware version to use. The available versions depend on the firmware type selected. " << DEFAULT_FIRMWARE_VERSION_NAME << " will select the most recent version available.\n"; - arg_description_stream << "\tMARLIN 1 versions: " << utilities::join(marlin_1_firmware.get_version_names(), ", ") << "\n"; - arg_description_stream << "\tMARLIN 2 versions: " << utilities::join(marlin_2_firmware.get_version_names(), ", ") << "\n"; - arg_description_stream << "\tREPETIER versions: " << utilities::join(repetier_firmware.get_version_names(), ", ") << "\n"; - arg_description_stream << "\tPRUSA versions: " << utilities::join(prusa_firmware.get_version_names(), ", ") << "\n"; - arg_description_stream << "\tSMOOTHIEWARE versions: " << utilities::join(smoothieware_firmware.get_version_names(), ", ") << "\n"; - arg_description_stream << "\tDefault Value: " << DEFAULT_FIRMWARE_VERSION_NAME; - TCLAP::ValueArg firmware_version_arg("v", "firmware-version", arg_description_stream.str(), false, DEFAULT_FIRMWARE_VERSION_NAME, "string"); - - // -p --print-firmware-defaults - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "Prints all available settings and defaults for the provided firmware type and version. If provided, all other parameters will be ignored except for " << firmware_type_arg.getName() << " and " << firmware_version_arg.getName() << "."; - TCLAP::SwitchArg print_firmware_defaults_arg("p", "print-firmware-defaults", arg_description_stream.str()); - - // -g --g90-influences-extruder - std::string g90_g91_influences_extruder_default_value = "DEFAULT"; - std::vector g90_g91_influences_extruder_vector; - g90_g91_influences_extruder_vector.push_back("TRUE"); - g90_g91_influences_extruder_vector.push_back("FALSE"); - g90_g91_influences_extruder_vector.push_back(g90_g91_influences_extruder_default_value); - TCLAP::ValuesConstraint g90_g91_influences_extruder_constraint(g90_g91_influences_extruder_vector); - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "Sets the firmware's G90/G91 influences extruder axis behavior. By default this is determined by the firmware's behavior. Default Value: " << g90_g91_influences_extruder_default_value; - TCLAP::ValueArg g90_arg("g", "g90-influences-extruder", arg_description_stream.str(), false, g90_g91_influences_extruder_default_value, &g90_g91_influences_extruder_constraint); - - // -m --mm-per-arc-segment - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The default segment length. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; - TCLAP::ValueArg mm_per_arc_segment_arg("m", "mm-per-arc-segment", arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); - - // max_arc_segment_mm_arg - // -d --max-arc-segment-mm - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The maximum length of an arc segment. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; - TCLAP::ValueArg max_arc_segment_mm_arg("d", "max-arc-segment-mm", arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); - - // -n --min-mm-per-arc-segment - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The minimum mm per arc segment. Used to prevent unnecessarily small segments from being generated. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_MM_PER_ARC_SEGMENT; - TCLAP::ValueArg min_mm_per_arc_segment_arg("n", "min-mm-per-arc-segment", arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); + } + TCLAP::ValuesConstraint firmware_type_constraint(firmware_types_vector); + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Sets the firmware to emulate. Default Value: " << firmware_type_names[DEFAULT_FIRMWARE_TYPE]; + std::string arg_name_firmare_type = "firmware-type"; + std::string arg_short_name_firmare_type = "f"; + TCLAP::ValueArg firmware_type_arg("f", "firmware-type", arg_description_stream.str(), false, firmware_type_names[DEFAULT_FIRMWARE_TYPE], &firmware_type_constraint); + + // -v --firmware-version + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Sets the firmware version to use. The available versions depend on the firmware type selected. " << DEFAULT_FIRMWARE_VERSION_NAME << " will select the most recent version available.\n"; + arg_description_stream << "\tMARLIN 1 versions: " << utilities::join(marlin_1_firmware.get_version_names(), ", ") << "\n"; + arg_description_stream << "\tMARLIN 2 versions: " << utilities::join(marlin_2_firmware.get_version_names(), ", ") << "\n"; + arg_description_stream << "\tREPETIER versions: " << utilities::join(repetier_firmware.get_version_names(), ", ") << "\n"; + arg_description_stream << "\tPRUSA versions: " << utilities::join(prusa_firmware.get_version_names(), ", ") << "\n"; + arg_description_stream << "\tSMOOTHIEWARE versions: " << utilities::join(smoothieware_firmware.get_version_names(), ", ") << "\n"; + arg_description_stream << "\tDefault Value: " << DEFAULT_FIRMWARE_VERSION_NAME; + std::string arg_name_firmare_version = "firmware-version"; + std::string arg_short_name_firmare_version = "v"; + TCLAP::ValueArg firmware_version_arg(arg_short_name_firmare_version, arg_name_firmare_version, arg_description_stream.str(), false, DEFAULT_FIRMWARE_VERSION_NAME, "string"); + + // -p --print-firmware-defaults + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Prints all available settings and defaults for the provided firmware type and version. If provided, all other parameters will be ignored except for " << firmware_type_arg.getName() << " and " << firmware_version_arg.getName() << "."; + std::string arg_name_print_firmware_defaults = "print-firmware-defaults"; + std::string arg_short_name_print_firmware_defaults = "p"; + TCLAP::SwitchArg print_firmware_defaults_arg(arg_short_name_print_firmware_defaults, arg_name_print_firmware_defaults, arg_description_stream.str()); + + // -g --g90-influences-extruder + std::string g90_g91_influences_extruder_default_value = "DEFAULT"; + std::vector g90_g91_influences_extruder_vector; + g90_g91_influences_extruder_vector.push_back("TRUE"); + g90_g91_influences_extruder_vector.push_back("FALSE"); + g90_g91_influences_extruder_vector.push_back(g90_g91_influences_extruder_default_value); + TCLAP::ValuesConstraint g90_g91_influences_extruder_constraint(g90_g91_influences_extruder_vector); + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Sets the firmware's G90/G91 influences extruder axis behavior. By default this is determined by the firmware's behavior. Default Value: " << g90_g91_influences_extruder_default_value; + std::string arg_name_g90_g91_influences_extruder = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg g90_arg("g", arg_name_g90_g91_influences_extruder, arg_description_stream.str(), false, g90_g91_influences_extruder_default_value, &g90_g91_influences_extruder_constraint); + + // -m --mm-per-arc-segment + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The default segment length. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; + std::string arg_name_mm_per_arc_segment = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg mm_per_arc_segment_arg("m", arg_name_mm_per_arc_segment, arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); + + // max_arc_segment_mm_arg -- same funciton as max_arc_segment_mm + // -d --max-arc-segment-mm + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The maximum length of an arc segment. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; + std::string arg_name_max_arc_segment_mm = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_MAX_ARC_SEGMENT_MM, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg max_arc_segment_mm_arg("d", arg_name_max_arc_segment_mm, arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); + + // arc_segments_per_r -- same funciton as max_arc_segment_mm + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The maximum length of an arc segment. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; + std::string arg_name_arc_segments_per_r = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_ARC_SEGMENT_PER_R, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg arc_segments_per_r_arg("i", arg_name_arc_segments_per_r, arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); + + // -n --min-mm-per-arc-segment + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum mm per arc segment. Used to prevent unnecessarily small segments from being generated. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_MM_PER_ARC_SEGMENT; + std::string arg_name_min_mm_per_arc_segment = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_MIN_MM_PER_ARC_SEGMENT, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg min_mm_per_arc_segment_arg("n", arg_name_min_mm_per_arc_segment, arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); + + // min_arc_segment_mm + // -b --min-arc-segment-mm + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum mm per arc segment. Used to prevent unnecessarily small segments from being generated. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_MM_PER_ARC_SEGMENT; + std::string arg_name_min_arc_segment_mm = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_MIN_ARC_SEGMENT_MM, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg min_arc_segment_mm_arg("b", arg_name_min_arc_segment_mm, arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); + + // -r --min-arc-segments + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum number of segments within a circle of the same radius as the arc. Can be used to increase detail on small arcs. The smallest segment generated will be no larger than min_mm_per_arc_segment. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_ARC_SEGMENTS; + std::string arg_name_min_arc_segments = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg min_arc_segments_arg("r", arg_name_min_arc_segments, arg_description_stream.str(), false, DEFAULT_MIN_ARC_SEGMENTS, "int"); + + // min_circle_segments_arg + // -a --min-circle-segments-arg + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum number of segments within a circle of the same radius as the arc. Can be used to increase detail on small arcs. The smallest segment generated will be no larger than min_mm_per_arc_segment. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_ARC_SEGMENTS; + std::string arg_name_min_circle_segments = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_MIN_CIRCLE_SEGMENTS, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg min_circle_segments_arg("a", arg_name_min_circle_segments, arg_description_stream.str(), false, DEFAULT_MIN_CIRCLE_SEGMENTS, "int"); + + // -c --n-arc-correction + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The number of segments that will be interpolated using a small angle approximation before true sin/cos corrections are applied. A value less than or equal to 1 will disable this feature. Default Value: " << DEFAULT_N_ARC_CORRECTIONS; + std::string arg_name_n_arc_correction = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_N_ARC_CORRECTION, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg n_arc_correction_arg("c", arg_name_n_arc_correction, arg_description_stream.str(), false, DEFAULT_N_ARC_CORRECTIONS, "int"); + + // -s --arc-segments-per-second + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The number of segments per second. This will produce a constant number of arcs, clamped between mm-per-arc-segment and min-mm-per-arc-segment. Can be used to prevent stuttering when printing very quickly. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_ARC_SEGMENTS_PER_SEC; + std::string arg_name_arc_segments_per_sec = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg arc_segments_per_sec_arg("s", arg_name_arc_segments_per_sec, arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); + + // -e --mm-max-arc-error + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "This currently is only used in Smoothieware. The maximum error for line segments that divide arcs. Set to 0 to disable. Default Value: " << DEFAULT_MM_MAX_ARC_ERROR; + std::string arg_name_mm_max_arc_error = firmware_arguments::get_argument_string(FIRMWARE_ARGUMENT_MM_MAX_ARC_ERROR, "", COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); + TCLAP::ValueArg mm_max_arc_error_arg("e", arg_name_mm_max_arc_error, arg_description_stream.str(), false, DEFAULT_MM_MAX_ARC_ERROR, "float"); + + // -l --log-level + std::vector log_levels_vector; + log_levels_vector.push_back("NOSET"); + log_levels_vector.push_back("VERBOSE"); + log_levels_vector.push_back("DEBUG"); + log_levels_vector.push_back("INFO"); + log_levels_vector.push_back("WARNING"); + log_levels_vector.push_back("ERROR"); + log_levels_vector.push_back("CRITICAL"); + log_levels_vector.push_back(""); + TCLAP::ValuesConstraint log_levels_constraint(log_levels_vector); + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "Sets console log level. Possible values: Default Value: " << log_level_string_default; + TCLAP::ValueArg 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); + cmd.add(firmware_type_arg); + cmd.add(firmware_version_arg); + cmd.add(g90_arg); + cmd.add(mm_per_arc_segment_arg); + cmd.add(min_mm_per_arc_segment_arg); + cmd.add(min_arc_segments_arg); + cmd.add(n_arc_correction_arg); + cmd.add(arc_segments_per_sec_arg); + cmd.add(log_level_arg); + cmd.add(min_circle_segments_arg); + cmd.add(min_arc_segment_mm_arg); + cmd.add(max_arc_segment_mm_arg); + cmd.add(arc_segments_per_r_arg); + cmd.add(print_firmware_defaults_arg); + cmd.add(mm_max_arc_error_arg); + + // First, we need to see if the user wants to print firmware defaults + help_cmd.add(firmware_type_arg); + help_cmd.add(firmware_version_arg); + help_cmd.add(print_firmware_defaults_arg); + help_cmd.ignoreUnmatched(true); + help_cmd.setExceptionHandling(false); + + - // min_arc_segment_mm - // -b --min-arc-segment-mm - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The minimum mm per arc segment. Used to prevent unnecessarily small segments from being generated. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_MM_PER_ARC_SEGMENT; - TCLAP::ValueArg min_arc_segment_mm_arg("b", "min-arc-segment-mm", arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); - - // -r --min-arc-segments - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The minimum number of segments within a circle of the same radius as the arc. Can be used to increase detail on small arcs. The smallest segment generated will be no larger than min_mm_per_arc_segment. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_ARC_SEGMENTS; - TCLAP::ValueArg min_arc_segments_arg("r", "min-arc-segments", arg_description_stream.str(), false, DEFAULT_MIN_ARC_SEGMENTS, "int"); - - // min_circle_segments_arg - // -a --min-circle-segments-arg - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The minimum number of segments within a circle of the same radius as the arc. Can be used to increase detail on small arcs. The smallest segment generated will be no larger than min_mm_per_arc_segment. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_ARC_SEGMENTS; - TCLAP::ValueArg min_circle_segments_arg("a", "min-circle-segments", arg_description_stream.str(), false, DEFAULT_MIN_CIRCLE_SEGMENTS, "int"); - - // -c --n-arc-correction - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The number of segments that will be interpolated using a small angle approximation before true sin/cos corrections are applied. A value less than or equal to 1 will disable this feature. Default Value: " << DEFAULT_N_ARC_CORRECTIONS; - TCLAP::ValueArg n_arc_correction_arg("c", "n-arc-correction", arg_description_stream.str(), false, DEFAULT_N_ARC_CORRECTIONS, "int"); - - // -s --arc-segments-per-second - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "The number of segments per second. This will produce a constant number of arcs, clamped between mm-per-arc-segment and min-mm-per-arc-segment. Can be used to prevent stuttering when printing very quickly. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_ARC_SEGMENTS_PER_SEC; - TCLAP::ValueArg arc_segments_per_sec_arg("s", "arc-segments-per-second", arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); - - // -e --mm-max-arc-error - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "This currently is only used in Smoothieware. The maximum error for line segments that divide arcs. Set to 0 to disable. Default Value: " << DEFAULT_MM_MAX_ARC_ERROR; - TCLAP::ValueArg mm_max_arc_error_arg("e", "mm-max-arc-error", arg_description_stream.str(), false, DEFAULT_MM_MAX_ARC_ERROR, "float"); - - // -l --log-level - std::vector log_levels_vector; - log_levels_vector.push_back("NOSET"); - log_levels_vector.push_back("VERBOSE"); - log_levels_vector.push_back("DEBUG"); - log_levels_vector.push_back("INFO"); - log_levels_vector.push_back("WARNING"); - log_levels_vector.push_back("ERROR"); - log_levels_vector.push_back("CRITICAL"); - log_levels_vector.push_back(""); - TCLAP::ValuesConstraint log_levels_constraint(log_levels_vector); - arg_description_stream.clear(); - arg_description_stream.str(""); - arg_description_stream << "Sets console log level. Possible values: Default Value: " << log_level_string_default; - TCLAP::ValueArg 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); - cmd.add(firmware_type_arg); - cmd.add(firmware_version_arg); - cmd.add(g90_arg); - cmd.add(mm_per_arc_segment_arg); - cmd.add(min_mm_per_arc_segment_arg); - cmd.add(min_arc_segments_arg); - cmd.add(n_arc_correction_arg); - cmd.add(arc_segments_per_sec_arg); - cmd.add(log_level_arg); - cmd.add(min_circle_segments_arg); - cmd.add(min_arc_segment_mm_arg); - cmd.add(max_arc_segment_mm_arg); - cmd.add(print_firmware_defaults_arg); - - // First, we need to see if the user wants to print firmware defaults - help_cmd.add(firmware_type_arg); - help_cmd.add(firmware_version_arg); - help_cmd.add(print_firmware_defaults_arg); - help_cmd.setExceptionHandling(false); + try { + + // parse the help requests try { help_cmd.parse(argc, argv); if (print_firmware_defaults_arg.isSet()) { + help_cmd.ignoreUnmatched(false); + help_cmd.reset(); + help_cmd.parse(argc, argv); std::string firmware_type_string = firmware_type_arg.getValue(); std::string firmware_version_string = firmware_version_arg.getValue(); print_firmware_defaults(firmware_type_string, firmware_version_string, firmware_version_arg.getName()); return 0; } } + catch (TCLAP::ArgException& exc) { - if (exc.argId() == "Argument: " + firmware_type_arg.toString() - || exc.argId() == "Argument: " + firmware_version_arg.toString()) + std::string argument_prefix = "Argument: "; + std::string firmware_type_arg_id = argument_prefix + arg_name_firmare_type; + std::string firmware_type_arg_id_short = argument_prefix + COMMAND_LINE_ARGUMENT_PREFIX_SHORT + arg_short_name_firmare_type + " (" + COMMAND_LINE_ARGUMENT_PREFIX + arg_name_firmare_type + ")"; + std::string firmware_version_arg_id = argument_prefix + arg_name_firmare_version; + std::string firmware_version_arg_id_short = argument_prefix + COMMAND_LINE_ARGUMENT_PREFIX_SHORT + arg_short_name_firmare_version + " (" + COMMAND_LINE_ARGUMENT_PREFIX + arg_name_firmare_version + ")";; + std::string exception_arg_id = exc.argId(); + + // If this is an exception related to the firmware-type or firmware-version args, print an error message for the + // thrown exception. Else, an invalid or extra argument must have been added, so add additional detail. + TCLAP::ArgException detailed_exception; + if (exception_arg_id == firmware_type_arg_id + || exception_arg_id == firmware_type_arg_id_short + || exception_arg_id == firmware_version_arg_id + || exception_arg_id == firmware_version_arg_id_short + ) { - // This will raise an exit exception - cmd.getOutput()->failure(cmd, exc); + detailed_exception = exc; } + else { + + std::string print_defaults_error_text = exc.error() + ". When the --" + arg_name_print_firmware_defaults + " (-" + arg_short_name_print_firmware_defaults + ") argument is supplied, only the --" + arg_name_firmare_type + " (-" + arg_short_name_firmare_type + ") and --" + arg_name_firmare_version + " (-" + arg_short_name_firmare_version + ") parameters are supported."; + TCLAP::ArgException print_defaults_parse_exception(print_defaults_error_text, exc.argId(), "Print Firmware Defaults Exception"); + detailed_exception = print_defaults_parse_exception; + // This will raise an exit exception + + } + cmd.getOutput()->failure(cmd, detailed_exception); + return 1; } // End print firmware defaults // Parse the argv array after resetting any used parameters. - firmware_type_arg.reset(); - firmware_version_arg.reset(); + cmd.reset(); cmd.parse(argc, argv); // Ok! Now let's see what firmware and version were selected, then we can start adding parameters // First, Set the firmware type std::string firmware_type_string = firmware_type_arg.getValue(); - firmware_types firmware_type = static_cast(get_firmware_type_from_string(firmware_type_string)); + args.firmware_args.firmware_type = static_cast(get_firmware_type_from_string(firmware_type_string)); // Now set the version // Set the firmware version, and check to make sure that the version supplied is supported. std::string firmware_version_string = firmware_version_arg.getValue(); - is_firmware_version_valid_for_type(firmware_type_string, firmware_version_string, firmware_version_arg.getName()); + check_firmware_version_for_type(firmware_type_string, firmware_version_string, firmware_version_arg.getName()); args.firmware_args.version = firmware_version_string; // now that we have the firmware type and version, we can extract the default arguments and override any settings that are supplied @@ -318,67 +380,73 @@ int run_arc_straightener(int argc, char* argv[]) args.target_path = args.source_path; } + // ensure the source file exists + if (!utilities::does_file_exist(args.source_path)) + { + throw TCLAP::ArgException("The source file does not exist at the specified path.", source_arg.getName()); + } + std::string available_arguments_string = args.firmware_args.get_available_arguments_string(COMMAND_LINE_ARGUMENT_SEPARATOR, COMMAND_LINE_ARGUMENT_PREFIX, COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); // If the arguments are set, apply them. If not, don't. if (mm_per_arc_segment_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("mm_per_arc_segment")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", mm_per_arc_segment_arg.getName(), "The argument does not apply to the " + firmware_type_string +" " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, mm_per_arc_segment_arg.toString()); } args.firmware_args.mm_per_arc_segment = mm_per_arc_segment_arg.getValue(); } if (min_mm_per_arc_segment_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("min_mm_per_arc_segment")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_MIN_MM_PER_ARC_SEGMENT)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", min_mm_per_arc_segment_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, min_mm_per_arc_segment_arg.toString()); } args.firmware_args.min_mm_per_arc_segment = min_mm_per_arc_segment_arg.getValue(); } if (min_arc_segments_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("min_arc_segments")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", min_arc_segments_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, min_arc_segments_arg.toString()); } args.firmware_args.min_arc_segments = min_arc_segments_arg.getValue(); } if (arc_segments_per_sec_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("arc_segments_per_sec")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", arc_segments_per_sec_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, arc_segments_per_sec_arg.toString() ); } args.firmware_args.arc_segments_per_sec = arc_segments_per_sec_arg.getValue(); } if (g90_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("g90_g91_influences_extruder")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", g90_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, g90_arg.toString()); } args.firmware_args.g90_g91_influences_extruder = g90_arg.getValue() == "TRUE"; } if (n_arc_correction_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("n_arc_correction")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_N_ARC_CORRECTION)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", n_arc_correction_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, n_arc_correction_arg.toString()); } args.firmware_args.n_arc_correction = n_arc_correction_arg.getValue(); } if (mm_max_arc_error_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("mm_max_arc_error")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_MM_MAX_ARC_ERROR)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", mm_max_arc_error_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, mm_max_arc_error_arg.toString()); } args.firmware_args.mm_max_arc_error = mm_max_arc_error_arg.getValue(); } @@ -387,32 +455,43 @@ int run_arc_straightener(int argc, char* argv[]) if (min_circle_segments_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("min_circle_segments")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_MIN_CIRCLE_SEGMENTS)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", min_circle_segments_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, min_circle_segments_arg.toString()); } - args.firmware_args.set_min_circle_segments(min_circle_segments_arg.getValue()); + args.firmware_args.min_circle_segments = min_circle_segments_arg.getValue(); } // min_arc_segment_mm if (min_arc_segment_mm_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("min_arc_segment_mm")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_MIN_ARC_SEGMENT_MM)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", min_arc_segment_mm_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, min_arc_segment_mm_arg.toString()); } - args.firmware_args.set_min_arc_segment_mm(min_arc_segment_mm_arg.getValue()); + args.firmware_args.min_arc_segment_mm = min_arc_segment_mm_arg.getValue(); } // max_arc_segment_mm if (max_arc_segment_mm_arg.isSet()) { // See if this argument is supported - if (!args.firmware_args.is_argument_used("max_arc_segment_mm")) + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_MAX_ARC_SEGMENT_MM)) { - throw new TCLAP::ArgException("Invalid Argument For Firmware", max_arc_segment_mm_arg.getName(), "The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + get_available_arguments_string(args.firmware_args.get_available_arguments())); + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, max_arc_segment_mm_arg.toString()); } - args.firmware_args.set_max_arc_segment_mm(max_arc_segment_mm_arg.getValue()); + args.firmware_args.max_arc_segment_mm = max_arc_segment_mm_arg.getValue(); + } + //arc_segments_per_r + if (arc_segments_per_r_arg.isSet()) + { + // See if this argument is supported + if (!args.firmware_args.is_argument_used(FIRMWARE_ARGUMENT_ARC_SEGMENT_PER_R)) + { + throw TCLAP::ArgException("The argument does not apply to the " + firmware_type_string + " " + firmware_version_arg.getValue() + " firmware. Only the following parameters are supported: " + available_arguments_string, arc_segments_per_r_arg.toString()); + } + args.firmware_args.arc_segments_per_r = arc_segments_per_r_arg.getValue(); } + log_level_string = log_level_arg.getValue(); log_level_value = -1; @@ -427,16 +506,21 @@ int run_arc_straightener(int argc, char* argv[]) if (log_level_value == -1) { // TODO: Does this work? - throw new TCLAP::ArgException("Unknown log level"); + throw TCLAP::ArgException("Unknown log level", log_level_arg.toString()); } } // catch argument exceptions catch (TCLAP::ArgException& e) { - std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; + // This will raise an exit exception + cmd.getOutput()->failure(cmd, e); return 1; } + catch (TCLAP::ExitException exc) + { + exit(exc.getExitStatus()); + } // Ensure the log level name is valid @@ -489,7 +573,8 @@ int run_arc_straightener(int argc, char* argv[]) } arc_interpolation interpolator(args); - log_messages << interpolator.get_firmware_argument_description(); + + log_messages << interpolator.get_firmware_arguments_description(COMMAND_LINE_ARGUMENT_SEPARATOR, COMMAND_LINE_ARGUMENT_PREFIX, COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); p_logger->log(0, log_levels::INFO, log_messages.str()); p_logger->log(0, log_levels::INFO, "Running interpolation..."); @@ -523,22 +608,6 @@ int run_arc_straightener(int argc, char* argv[]) } - -std::string get_available_arguments_string(std::vector firmware_arguments) -{ - std::string available_argument_string = ""; - - for (std::vector::iterator it = firmware_arguments.begin(); it != firmware_arguments.end(); it++) - { - if (available_argument_string.size() > 0) - { - available_argument_string += ", "; - } - available_argument_string += "--" +utilities::replace(*it, "_", "-"); - } - return available_argument_string; -} - int get_firmware_type_from_string(std::string firmware_type) { for (int i = 0; i < NUM_FIRMWARE_TYPES; i++) @@ -552,7 +621,7 @@ int get_firmware_type_from_string(std::string firmware_type) return static_cast(DEFAULT_FIRMWARE_TYPE); } -bool is_firmware_version_valid_for_type(std::string firmware_type_string, std::string firmware_version, std::string firmware_version_arg_name) +void check_firmware_version_for_type(std::string firmware_type_string, std::string firmware_version, std::string firmware_version_arg_name) { firmware_types firmware_type = static_cast(get_firmware_type_from_string(firmware_type_string)); // Create an instance of all supported firmware types using the default args @@ -568,33 +637,36 @@ bool is_firmware_version_valid_for_type(std::string firmware_type_string, std::s case firmware_types::MARLIN_1: if (!marlin_1_firmware.is_valid_version(firmware_version)) { - throw new TCLAP::ArgException("Unknown Version Exception", firmware_version_arg_name, "'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type."); + + throw TCLAP::ArgException("'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type. The available versions are: " + marlin_1_firmware.get_version_names_string(), firmware_version_arg_name); } break; case firmware_types::MARLIN_2: if (!marlin_2_firmware.is_valid_version(firmware_version)) { - throw new TCLAP::ArgException("Unknown Version Exception", firmware_version_arg_name, "'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type."); + throw TCLAP::ArgException("'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type. The available versions are: " + marlin_2_firmware.get_version_names_string(), firmware_version_arg_name ); } break; case firmware_types::REPETIER: if (!repetier_firmware.is_valid_version(firmware_version)) { - throw new TCLAP::ArgException("Unknown Version Exception", firmware_version_arg_name, "'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type."); + throw TCLAP::ArgException("'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type. The available versions are: " + repetier_firmware.get_version_names_string(), firmware_version_arg_name); } break; case firmware_types::PRUSA: if (!prusa_firmware.is_valid_version(firmware_version)) { - throw new TCLAP::ArgException("Unknown Version Exception", firmware_version_arg_name, "'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type."); + throw TCLAP::ArgException("'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type. The available versions are: " + prusa_firmware.get_version_names_string(), firmware_version_arg_name ); } break; case firmware_types::SMOOTHIEWARE: if (!smoothieware_firmware.is_valid_version(firmware_version)) { - throw new TCLAP::ArgException("Unknown Version Exception", firmware_version_arg_name, "'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type."); + throw TCLAP::ArgException("'" + firmware_version + "' is not a valid version for " + firmware_type_string + " firmware type. The available versions are: " + smoothieware_firmware.get_version_names_string(), firmware_version_arg_name); } break; + default: + throw TCLAP::ArgException("The supplied firmmware type " + firmware_type_string + " is unknown. The available versions are: " + smoothieware_firmware.get_version_names_string(), firmware_version_arg_name); } } @@ -610,7 +682,7 @@ void print_firmware_defaults(std::string firmware_type_string, std::string firmw firmware_types firmware_type = static_cast(get_firmware_type_from_string(firmware_type_string)); args.firmware_args.firmware_type = firmware_type; - is_firmware_version_valid_for_type(firmware_type_string, firmware_version_string, firmware_version_arg_name); + check_firmware_version_for_type(firmware_type_string, firmware_version_string, firmware_version_arg_name); args.firmware_args.version = firmware_version_string; // now that we have the firmware type and version, we can extract the default arguments and override any settings that are supplied @@ -639,6 +711,6 @@ void print_firmware_defaults(std::string firmware_type_string, std::string firmw } std::cout << "Showing arguments and defaults for " << firmware_type_string << " (" << firmware_version_string << ")\n"; - std::cout << "Available argument for firmware: " << get_available_arguments_string(args.firmware_args.get_available_arguments()) << "\n"; - std::cout << "Default " << args.firmware_args.get_argument_description(); + std::cout << "Available argument for firmware: " << args.firmware_args.get_available_arguments_string(COMMAND_LINE_ARGUMENT_SEPARATOR, COMMAND_LINE_ARGUMENT_PREFIX, COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE) << "\n"; + std::cout << "Default " << args.firmware_args.get_arguments_description(COMMAND_LINE_ARGUMENT_SEPARATOR, COMMAND_LINE_ARGUMENT_PREFIX, COMMAND_LINE_ARGUMENT_REPLACEMENT_STRING, COMMAND_LINE_ARGUMENT_REPLACEMENT_VALUE); } \ No newline at end of file diff --git a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.h b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.h index 0b2ca1a..f128e33 100644 --- a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.h +++ b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.h @@ -35,8 +35,7 @@ #include #include int run_arc_straightener(int argc, char* argv[]); -static std::string get_available_arguments_string(std::vector firmware_arguments); -static bool is_firmware_version_valid_for_type(std::string firmware_type_string, std::string firmware_version, std::string firmware_version_arg_name); +static void check_firmware_version_for_type(std::string firmware_type_string, std::string firmware_version, std::string firmware_version_arg_name); static int get_firmware_type_from_string(std::string firmware_type); static void print_firmware_defaults(std::string firmware_type_string, std::string firmware_version_string, std::string firmware_version_arg_name); diff --git a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.vcxproj b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.vcxproj index 334d94e..b6dc2d2 100644 --- a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.vcxproj +++ b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.vcxproj @@ -106,10 +106,12 @@ true $(SolutionDir)\GcodeProcessorLib\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\ + ArcStraightener true $(SolutionDir)\GcodeProcessorLib\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\ + ArcStraightener false @@ -119,6 +121,7 @@ false $(SolutionDir)\GcodeProcessorLib\;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)\TCLAP\ $(VC_ExecutablePath_x64);$(CommonExecutablePath) + ArcStraightener diff --git a/ArcWelderInverseProcessor/arc_interpolation.cpp b/ArcWelderInverseProcessor/arc_interpolation.cpp index c5cde1a..feb045b 100644 --- a/ArcWelderInverseProcessor/arc_interpolation.cpp +++ b/ArcWelderInverseProcessor/arc_interpolation.cpp @@ -152,6 +152,8 @@ void arc_interpolation::process() { if (output_file_.is_open()) { + // Add the gcode file header + output_file_ << p_current_firmware_->get_gcode_header_comment()<<"\n"; parsed_command cmd; // Communicate every second while (std::getline(gcode_file, line)) @@ -273,7 +275,7 @@ void arc_interpolation::process() std::cout << stream.str(); } -std::string arc_interpolation::get_firmware_argument_description() const +std::string arc_interpolation::get_firmware_arguments_description(std::string separator, std::string argument_prefix, std::string replacement_string, std::string replacement_value) const { - return p_current_firmware_->get_argument_description(); + return p_current_firmware_->get_arguments_description(separator, argument_prefix, replacement_string, replacement_value); } \ No newline at end of file diff --git a/ArcWelderInverseProcessor/arc_interpolation.h b/ArcWelderInverseProcessor/arc_interpolation.h index d3eb306..e1eed16 100644 --- a/ArcWelderInverseProcessor/arc_interpolation.h +++ b/ArcWelderInverseProcessor/arc_interpolation.h @@ -74,7 +74,7 @@ class arc_interpolation /// Outputs a string description of the firmware arguments. /// /// - std::string get_firmware_argument_description() const; + std::string get_firmware_arguments_description(std::string separator = "", std::string argument_prefix = "", std::string replacement_string = "", std::string replacement_value = "") const; private: arc_interpolation_args args_; gcode_position_args get_args_(bool g90_g91_influences_extruder, int buffer_size); diff --git a/ArcWelderInverseProcessor/firmware.cpp b/ArcWelderInverseProcessor/firmware.cpp index 5025c2f..bab3968 100644 --- a/ArcWelderInverseProcessor/firmware.cpp +++ b/ArcWelderInverseProcessor/firmware.cpp @@ -105,7 +105,7 @@ std::string firmware::g1_command(firmware_position& target) if (has_e) { gcode += is_first_parameter ? "E" : " E"; - gcode += utilities::dtos(state_.is_extruder_relative ? target.e - position_.e : target.e, 3); + gcode += utilities::dtos(state_.is_extruder_relative ? target.e - position_.e : target.e, 5); is_first_parameter = false; } @@ -139,14 +139,41 @@ std::vector firmware::get_version_names() return version_names_; } +std::string firmware::get_version_names_string() +{ + std::vector version_names_with_release_info; + bool foundLatestRelease = false; + for (int index = 0; index < version_names_.size(); index++) + { + std::string version_name = version_names_[index]; + + if (foundLatestRelease) + { + version_name.append(" (").append("NON_RELEASE_VERSION").append(")"); + } + else if (version_name == args_.latest_release_version) + { + version_name.append(" (").append(LATEST_FIRMWARE_VERSION_NAME).append(")"); + foundLatestRelease = true; + } + version_names_with_release_info.push_back(version_name); + } + return utilities::join(version_names_with_release_info, ","); +} + bool firmware::get_g90_g91_influences_extruder() { return args_.g90_g91_influences_extruder; } -std::string firmware::get_argument_description() { +std::string firmware::get_arguments_description(std::string separator, std::string argument_prefix, std::string replacement_string, std::string replacement_value) { - return args_.get_argument_description(); + return args_.get_arguments_description(separator, argument_prefix, replacement_string, replacement_value); +} + +std::string firmware::get_gcode_header_comment() +{ + return args_.get_gcode_header_comment(); } void firmware::set_versions(std::vector version_names, std::string latest_release_version_name) diff --git a/ArcWelderInverseProcessor/firmware.h b/ArcWelderInverseProcessor/firmware.h index d2f7f2d..3113539 100644 --- a/ArcWelderInverseProcessor/firmware.h +++ b/ArcWelderInverseProcessor/firmware.h @@ -37,25 +37,29 @@ #include #include #include +#include +#include "version.h" #define DEFAULT_FIRMWARE_TYPE firmware_types::MARLIN_2 #define LATEST_FIRMWARE_VERSION_NAME "LATEST_RELEASE" #define DEFAULT_FIRMWARE_VERSION_NAME LATEST_FIRMWARE_VERSION_NAME // Arc interpretation settings: -#define DEFAULT_MM_PER_ARC_SEGMENT 1.0 // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_ARC_SEGMENTS_PER_R 0; +#define DEFAULT_MM_PER_ARC_SEGMENT 0 // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_ARC_SEGMENTS_PER_R 0; // 0 to disable +#define DEFAULT_MAX_MM_PER_ARC_SEGMENT 0 // Required - The enforced maximum length of an arc segment +#define DEFAULT_MIN_ARC_SEGMENT_MM 0; // 0 to disable #define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0 /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ - // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 24 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_MIN_CIRCLE_SEGMENTS 72 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. + // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. Set to 0 to disable +#define DEFAULT_MIN_ARC_SEGMENTS 0 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. Set to 0 to disable. +#define DEFAULT_MIN_CIRCLE_SEGMENTS 0 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. #define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. -// approximation will not be used for the first segment. Subsequent segments will be corrected following DEFAULT_N_ARC_CORRECTION. -#define DEFAULT_N_ARC_CORRECTIONS 24 +// approximation will not be used for the first segment. Subsequent segments will be corrected following DEFAULT_N_ARC_CORRECTION. Set to 0 to disable. +#define DEFAULT_N_ARC_CORRECTIONS 0 // This setting is for the gcode position processor to help interpret G90/G91 behavior #define DEFAULT_G90_G91_INFLUENCES_EXTRUDER false // This currently is only used in Smoothieware. The maximum error for line segments that divide arcs. Set to 0 to disable. -#define DEFAULT_MM_MAX_ARC_ERROR 0.01 +#define DEFAULT_MM_MAX_ARC_ERROR 0 struct firmware_state { firmware_state() { @@ -81,13 +85,29 @@ struct firmware_position { double f; }; +// parameter name defines +#define FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT "mm_per_arc_segment" +#define FIRMWARE_ARGUMENT_ARC_SEGMENT_PER_R "arc_segments_per_r" +#define FIRMWARE_ARGUMENT_MIN_MM_PER_ARC_SEGMENT "min_mm_per_arc_segment" +#define FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS "min_arc_segments" +#define FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC "arc_segments_per_sec" +#define FIRMWARE_ARGUMENT_N_ARC_CORRECTION "n_arc_correction" +#define FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER "g90_g91_influences_extruder" +#define FIRMWARE_ARGUMENT_MM_MAX_ARC_ERROR "mm_max_arc_error" +#define FIRMWARE_ARGUMENT_MIN_CIRCLE_SEGMENTS "min_circle_segments" +#define FIRMWARE_ARGUMENT_MIN_ARC_SEGMENT_MM "min_arc_segment_mm" +#define FIRMWARE_ARGUMENT_MAX_ARC_SEGMENT_MM "max_arc_segment_mm" + struct firmware_arguments { public: - + firmware_arguments() { mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; + min_arc_segment_mm = DEFAULT_MIN_ARC_SEGMENT_MM; + max_arc_segment_mm = DEFAULT_MAX_MM_PER_ARC_SEGMENT; arc_segments_per_r = DEFAULT_ARC_SEGMENTS_PER_R; min_mm_per_arc_segment = DEFAULT_MIN_MM_PER_ARC_SEGMENT; + min_circle_segments = DEFAULT_MIN_CIRCLE_SEGMENTS; min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; n_arc_correction = DEFAULT_N_ARC_CORRECTIONS; @@ -99,17 +119,17 @@ public: // add a list of all possible arguments, including aliases all_arguments_.clear(); - all_arguments_.push_back("mm_per_arc_segment"); - all_arguments_.push_back("arc_segments_per_r"); - all_arguments_.push_back("min_mm_per_arc_segment"); - all_arguments_.push_back("min_arc_segments"); - all_arguments_.push_back("arc_segments_per_sec"); - all_arguments_.push_back("n_arc_correction"); - all_arguments_.push_back("g90_g91_influences_extruder"); - all_arguments_.push_back("mm_max_arc_error"); - all_arguments_.push_back("min_circle_segments"); - all_arguments_.push_back("min_arc_segment_mm"); - all_arguments_.push_back("max_arc_segment_mm"); + all_arguments_.push_back(FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT); + all_arguments_.push_back(FIRMWARE_ARGUMENT_ARC_SEGMENT_PER_R); + all_arguments_.push_back(FIRMWARE_ARGUMENT_MIN_MM_PER_ARC_SEGMENT); + all_arguments_.push_back(FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS); + all_arguments_.push_back(FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC); + all_arguments_.push_back(FIRMWARE_ARGUMENT_N_ARC_CORRECTION); + all_arguments_.push_back(FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER); + all_arguments_.push_back(FIRMWARE_ARGUMENT_MM_MAX_ARC_ERROR); + all_arguments_.push_back(FIRMWARE_ARGUMENT_MIN_CIRCLE_SEGMENTS); + all_arguments_.push_back(FIRMWARE_ARGUMENT_MIN_ARC_SEGMENT_MM); + all_arguments_.push_back(FIRMWARE_ARGUMENT_MAX_ARC_SEGMENT_MM); }; /// @@ -124,10 +144,21 @@ public: /// The minimum mm per arc segment. If less than or equal to 0, this is disabled /// double min_mm_per_arc_segment; + /// + /// The minimum mm per arc segment. If less than or equal to 0, this is disabled + /// + double min_arc_segment_mm; + /// + /// The maximum mm per arc segment. + /// + double max_arc_segment_mm; + + /// /// The number of arc segments that will be drawn per second based on the given feedrate. /// If less than or equal to zero, this is disabled. /// + double arc_segments_per_sec; /// /// This currently is only used in Smoothieware. The maximum error for line segments that divide arcs. Set to 0 to disable. @@ -138,6 +169,12 @@ public: /// If less than or equal to zero, this is disabled /// int min_arc_segments; + + /// + /// The minimum number of arc segments in a full circle of the arc's radius. + /// If less than or equal to zero, this is disabled + /// + int min_circle_segments; /// /// // Number of interpolated segments before true sin and cos corrections will be applied. /// If less than or equal to zero, true sin and cos will always be used. @@ -160,36 +197,7 @@ public: /// True if the current version is the latest release. For informational purposes only /// std::string latest_release_version; - /// Aliases for variour parameters - int get_min_circle_segments() const - { - return min_arc_segments; - } - void set_min_circle_segments(int segments) - { - min_arc_segments = segments; - } - - double get_min_arc_segment_mm() const - { - return min_mm_per_arc_segment; - } - - void set_min_arc_segment_mm(double mm) - { - min_mm_per_arc_segment = mm; - } - - double get_max_arc_segment_mm() const - { - return mm_per_arc_segment; - } - - void set_max_arc_segment_mm(double mm) - { - mm_per_arc_segment = mm; - } - + void set_used_arguments(std::vector arguments) { used_arguments_ = arguments; @@ -208,91 +216,180 @@ public: return unused_arguments; } - std::string get_unused_arguments_string() + std::string get_unused_arguments_string(std::string separator = "", std::string argument_prefix = "", std::string replacement_string = "", std::string replacement_value = "") { + return get_arguments_string_(get_unused_arguments(), separator, argument_prefix, replacement_string, replacement_value); std::string unusaed_argument_string = ""; std::vector unused_argumnts = get_unused_arguments(); for (std::vector::iterator it = unused_argumnts.begin(); it != unused_argumnts.end(); it++) { if (unusaed_argument_string.size() > 0) { - unusaed_argument_string += ", "; + unusaed_argument_string += separator; } unusaed_argument_string += *it; } return unusaed_argument_string; } + std::string get_available_arguments_string(std::string separator = "", std::string argument_prefix = "", std::string replacement_string = "", std::string replacement_value = "") + { + return get_arguments_string_(used_arguments_, separator, argument_prefix, replacement_string, replacement_value); + } + std::vector get_available_arguments() { return used_arguments_; } + std::string get_gcode_header_comment() + { + std::string comment_start = "; "; + std::stringstream stream; + stream << comment_start << "Postprocessed by [ArcStraightener](https://github.com/FormerLurker/ArcWelderLib)\n"; + stream << comment_start << "Copyright(C) " << COPYRIGHT_DATE << " - " << AUTHOR << "\n"; + stream << comment_start << "Version: " << GIT_TAGGED_VERSION << ", Branch: " << GIT_BRANCH << ", BuildDate: " << BUILD_DATE << "\n"; + + stream << comment_start << "firmware_type=" << firmware_type_names[firmware_type] << "\n"; + stream << comment_start << "firmware_version=" << (version == LATEST_FIRMWARE_VERSION_NAME || version == latest_release_version ? latest_release_version + " (" + LATEST_FIRMWARE_VERSION_NAME + ")" : version) << "\n"; + + stream << std::fixed << std::setprecision(0); + std::string argument_string; + + // Bool values + argument_string = FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << (g90_g91_influences_extruder ? "True" : "False") << "\n"; + } + + // Int values + argument_string = FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << min_arc_segments << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_MIN_CIRCLE_SEGMENTS; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << min_circle_segments << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_N_ARC_CORRECTION; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << n_arc_correction << "\n"; + } + + stream << std::fixed << std::setprecision(2); + // Double values + argument_string = FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << mm_per_arc_segment << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_ARC_SEGMENT_PER_R; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << arc_segments_per_r << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << arc_segments_per_sec << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_MM_MAX_ARC_ERROR; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << mm_max_arc_error << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_MIN_MM_PER_ARC_SEGMENT; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << min_mm_per_arc_segment << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_MIN_ARC_SEGMENT_MM; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << min_arc_segment_mm << "\n"; + } + argument_string = FIRMWARE_ARGUMENT_MAX_ARC_SEGMENT_MM; + if (is_argument_used(argument_string)) + { + stream << comment_start << argument_string << "=" << max_arc_segment_mm << "\n"; + } + + return stream.str(); + } - std::string get_argument_description() { + std::string get_arguments_description(std::string separator="", std::string argument_prefix = "", std::string replacement_string = "", std::string replacement_value = "") { std::stringstream stream; stream << "Firmware Arguments:\n"; stream << "\tFirmware Type : " << firmware_type_names[firmware_type] << "\n"; stream << "\tFirmware Version : " << (version == LATEST_FIRMWARE_VERSION_NAME || version == latest_release_version ? latest_release_version + " (" + LATEST_FIRMWARE_VERSION_NAME + ")" : version) <<"\n"; stream << std::fixed << std::setprecision(0); + std::string argument_string; + // Bool values - if (is_argument_used("g90_g91_influences_extruder")) + argument_string = FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER; + if (is_argument_used(argument_string)) { - stream << "\tg90_g91_influences_extruder : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; } // Int values - if (is_argument_used("min_arc_segments")) + argument_string = FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS; + if (is_argument_used(argument_string)) { - stream << "\tmin_arc_segments : " << min_arc_segments << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << min_arc_segments << "\n"; } - if (is_argument_used("min_circle_segments")) + argument_string = FIRMWARE_ARGUMENT_MIN_CIRCLE_SEGMENTS; + if (is_argument_used(argument_string)) { - stream << "\tmin_circle_segments : " << get_min_circle_segments() << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << min_circle_segments << "\n"; } - if (is_argument_used("n_arc_correction")) + argument_string = FIRMWARE_ARGUMENT_N_ARC_CORRECTION; + if (is_argument_used(argument_string)) { - stream << "\tn_arc_correction : " << n_arc_correction << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << n_arc_correction << "\n"; } stream << std::fixed << std::setprecision(2); // Double values - // - if (is_argument_used("mm_per_arc_segment")) + argument_string = FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT; + if (is_argument_used(argument_string)) { - stream << "\tmm_per_arc_segment : " << mm_per_arc_segment << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << mm_per_arc_segment << "\n"; } - // - if (is_argument_used("arc_segments_per_r")) + argument_string = FIRMWARE_ARGUMENT_ARC_SEGMENT_PER_R; + if (is_argument_used(argument_string)) { - stream << "\tarc_segments_per_r : " << arc_segments_per_r << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << arc_segments_per_r << "\n"; } - // - if (is_argument_used("min_mm_per_arc_segment")) + argument_string = FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC; + if (is_argument_used(argument_string)) { - stream << "\tmin_mm_per_arc_segment : " << min_mm_per_arc_segment << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << arc_segments_per_sec << "\n"; } - // - if (is_argument_used("arc_segments_per_sec")) + argument_string = FIRMWARE_ARGUMENT_MM_MAX_ARC_ERROR; + if (is_argument_used(argument_string)) { - stream << "\tarc_segments_per_sec : " << arc_segments_per_sec << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << mm_max_arc_error << "\n"; } - // - if (is_argument_used("mm_max_arc_error")) + argument_string = FIRMWARE_ARGUMENT_MIN_MM_PER_ARC_SEGMENT; + if (is_argument_used(argument_string)) { - stream << "\tmm_max_arc_error : " << mm_max_arc_error << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << min_mm_per_arc_segment << "\n"; } - // - if (is_argument_used("min_arc_segment_mm")) + argument_string = FIRMWARE_ARGUMENT_MIN_ARC_SEGMENT_MM; + if (is_argument_used(argument_string)) { - stream << "\tmin_arc_segment_mm : " << get_min_arc_segment_mm() << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << min_arc_segment_mm << "\n"; } - // - if (is_argument_used("max_arc_segment_mm")) + argument_string = FIRMWARE_ARGUMENT_MAX_ARC_SEGMENT_MM; + if (is_argument_used(argument_string)) { - stream << "\tmax_arc_segment_mm : " << get_max_arc_segment_mm() << "\n"; + stream << "\t" << get_argument_string(argument_string, "", replacement_string, replacement_value) << " : " << max_arc_segment_mm << "\n"; } - - std::string unused_argument_string = get_unused_arguments_string(); + std::string unused_argument_string = get_unused_arguments_string(separator, argument_prefix, replacement_string, replacement_value); if (unused_argument_string.size() > 0) { stream << "The following parameters do not apply to this firmware version: " << unused_argument_string << "\n"; @@ -304,9 +401,29 @@ public: { return (std::find(used_arguments_.begin(), used_arguments_.end(), argument_name) != used_arguments_.end()); } + static std::string get_argument_string(std::string argument_name, std::string argument_prefix, std::string replacement_string = "", std::string replacement_value = "") + { + return argument_prefix + utilities::replace(argument_name, replacement_string, replacement_value); + } + private: std::vector all_arguments_; std::vector used_arguments_; + std::string get_arguments_string_(std::vector string_values, std::string separator, std::string argument_prefix, std::string replacement_string = "", std::string replacement_value = "") + { + std::string available_argument_string = ""; + + for (std::vector::iterator it = string_values.begin(); it != string_values.end(); it++) + { + if (available_argument_string.size() > 0) + { + available_argument_string += separator; + } + available_argument_string += get_argument_string(*it, argument_prefix , replacement_string, replacement_value); + } + return available_argument_string; + } + }; @@ -363,6 +480,12 @@ public: /// Vector of strings, one for each supported version std::vector get_version_names(); + /// + /// Returns all valid versions for this firmware in one comma separated string. + /// + /// Vector of strings, one for each supported version + std::string get_version_names_string(); + /// /// Returns the current g90_g91_influences_extruder value for the firmware. /// @@ -379,7 +502,13 @@ public: /// Outputs a string description of the firmware arguments. /// /// - std::string get_argument_description(); + std::string get_arguments_description(std::string separator , std::string argument_prefix = "", std::string replacement_string = "", std::string replacement_value = ""); + + /// + /// Returns a gcode comment containing the current settings + /// + /// + std::string get_gcode_header_comment(); /// /// Sets all available versions names and the version index based on args_.version @@ -387,8 +516,7 @@ public: /// void set_versions(std::vector version_names, std::string latest_release_version_name); - virtual firmware_arguments get_default_arguments_for_current_version()const; - + virtual firmware_arguments get_default_arguments_for_current_version() const; void set_arguments(firmware_arguments args); diff --git a/ArcWelderInverseProcessor/marlin_1.cpp b/ArcWelderInverseProcessor/marlin_1.cpp index b807abd..3bdf86f 100644 --- a/ArcWelderInverseProcessor/marlin_1.cpp +++ b/ArcWelderInverseProcessor/marlin_1.cpp @@ -58,7 +58,7 @@ void marlin_1::apply_arguments() { default:*/ plan_arc_ = &marlin_1::plan_arc_1_1_9_1; - used_arguments = { "mm_per_arc_segment", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; //break; //} @@ -78,14 +78,7 @@ firmware_arguments marlin_1::get_default_arguments_for_current_version() const //default: // Active Settings default_args.mm_per_arc_segment = 1.0f; - default_args.min_arc_segments = 24; default_args.n_arc_correction = 25; - // Inactive Settings - default_args.arc_segments_per_r = 0; - default_args.min_mm_per_arc_segment = 0; - default_args.arc_segments_per_sec = 0; - // Settings that do not apply - default_args.mm_max_arc_error = 0; //break; //} diff --git a/ArcWelderInverseProcessor/marlin_2.cpp b/ArcWelderInverseProcessor/marlin_2.cpp index fe66486..e70c043 100644 --- a/ArcWelderInverseProcessor/marlin_2.cpp +++ b/ArcWelderInverseProcessor/marlin_2.cpp @@ -55,11 +55,11 @@ void marlin_2::apply_arguments() switch (marlin_2_version_) { case marlin_2::marlin_2_firmware_versions::V2_0_9_2: - used_arguments = {"min_arc_segment_mm", "max_arc_segment_mm", "min_circle_segments", "arc_segments_per_sec", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MIN_ARC_SEGMENT_MM, FIRMWARE_ARGUMENT_MAX_ARC_SEGMENT_MM, FIRMWARE_ARGUMENT_MIN_CIRCLE_SEGMENTS, FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; plan_arc_ = &marlin_2::plan_arc_2_0_9_2; break; default: - used_arguments = { "mm_per_arc_segment", "arc_segments_per_r", "min_arc_segments", "arc_segments_per_sec", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_ARC_SEGMENT_PER_R, FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS, FIRMWARE_ARGUMENT_ARC_SEGMENTS_PER_SEC, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; plan_arc_ = &marlin_2::plan_arc_2_0_9_1; break; } @@ -78,15 +78,13 @@ firmware_arguments marlin_2::get_default_arguments_for_current_version() const { case marlin_2::marlin_2_firmware_versions::V2_0_9_2: // Active Settings - default_args.set_min_arc_segment_mm(0.1f); - default_args.set_max_arc_segment_mm(1.0f); - default_args.set_min_circle_segments(72); + default_args.min_arc_segment_mm = 0.1f; + default_args.max_arc_segment_mm = 1.0f; + default_args.min_circle_segments = 72; default_args.n_arc_correction = 25; // Inactive Settings default_args.arc_segments_per_r = 0; default_args.arc_segments_per_sec = 0; - // Settings that do not apply - default_args.mm_max_arc_error = 0; break; default: // Active Settings @@ -95,10 +93,7 @@ firmware_arguments marlin_2::get_default_arguments_for_current_version() const default_args.n_arc_correction = 25; // Inactive Settings default_args.arc_segments_per_r = 0; - default_args.min_mm_per_arc_segment = 0; default_args.arc_segments_per_sec = 0; - // Settings that do not apply - default_args.mm_max_arc_error = 0; break; } return default_args; @@ -340,7 +335,7 @@ void marlin_2::plan_arc_2_0_9_1( /// -/// This function was adapted from the 2.0.9.1 release of Marlin firmware, which can be found at the following link: +/// This function was adapted from the 2.0.9.2 release of Marlin firmware, which can be found at the following link: /// https://github.com/MarlinFirmware/Marlin/blob/b878127ea04cc72334eb35ce0dca39ccf7d73a68/Marlin/src/gcode/motion/G2_G3.cpp /// Copyright Notice found on that page: /// @@ -374,7 +369,7 @@ void marlin_2::plan_arc_2_0_9_2( const uint8_t circles // Take the scenic route ) { - int min_circle_segments = args_.get_min_circle_segments() > 0 ? args_.get_min_circle_segments() : 1; + int min_circle_segments = args_.min_circle_segments > 0 ? args_.min_circle_segments : 1; uint8_t p_axis = X_AXIS, q_axis = Y_AXIS, l_axis = Z_AXIS; // Radius vector from center to current location @@ -436,16 +431,16 @@ void marlin_2::plan_arc_2_0_9_2( // Get the nominal segment length based on settings float nominal_segment_mm; if (args_.arc_segments_per_sec > 0) { - nominal_segment_mm = utilities::constrainf(scaled_fr_mm_s * utilities::reciprocalf((float)args_.arc_segments_per_sec), (float)args_.get_min_arc_segment_mm(), (float)args_.get_max_arc_segment_mm()); + nominal_segment_mm = utilities::constrainf(scaled_fr_mm_s * utilities::reciprocalf((float)args_.arc_segments_per_sec), (float)args_.min_arc_segment_mm, (float)args_.max_arc_segment_mm); } else { - nominal_segment_mm = (float)args_.get_max_arc_segment_mm(); + nominal_segment_mm = (float)args_.max_arc_segment_mm; } // Number of whole segments based on the nominal segment length const float nominal_segments = utilities::maxf(utilities::floorf(flat_mm / nominal_segment_mm), min_segments); // A new segment length based on the required minimum - const float segment_mm = utilities::constrainf(flat_mm / nominal_segments, (float)args_.get_min_arc_segment_mm(), (float)args_.get_max_arc_segment_mm()); + const float segment_mm = utilities::constrainf(flat_mm / nominal_segments, (float)args_.min_arc_segment_mm, (float)args_.max_arc_segment_mm); // The number of whole segments in the arc, ignoring the remainder uint16_t segments = (uint16_t)utilities::floorf(flat_mm / segment_mm); diff --git a/ArcWelderInverseProcessor/prusa.cpp b/ArcWelderInverseProcessor/prusa.cpp index b1d5ac3..085977e 100644 --- a/ArcWelderInverseProcessor/prusa.cpp +++ b/ArcWelderInverseProcessor/prusa.cpp @@ -52,20 +52,14 @@ void prusa::apply_arguments() { case prusa::prusa_firmware_versions::V3_11_0: mc_arc_ = &prusa::mc_arc_3_11_0; - used_arguments = { "mm_per_arc_segment", "min_arc_segments", "min_mm_per_arc_segment", "mm_per_arc_segment", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_MIN_ARC_SEGMENTS, FIRMWARE_ARGUMENT_MIN_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; break; default: mc_arc_ = &prusa::mc_arc_3_10_0; - used_arguments = { "mm_per_arc_segment", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; break; } args_.set_used_arguments(used_arguments); - cs.arc_segments_per_sec = args_.arc_segments_per_sec; - cs.min_arc_segments = args_.min_arc_segments; - cs.min_mm_per_arc_segment = (float)args_.min_mm_per_arc_segment; - cs.mm_per_arc_segment = (float)args_.mm_per_arc_segment; - cs.n_arc_correction = args_.n_arc_correction; - } @@ -196,7 +190,7 @@ void prusa::mc_arc_3_10_0(float* position, float* target, float* offset, float f float millimeters_of_travel = (float)utilities::hypot((double)angular_travel * radius, utilities::absf(linear_travel)); if (millimeters_of_travel < 0.001) { return; } - uint16_t segments = (uint16_t)utilities::floorf(millimeters_of_travel / cs.mm_per_arc_segment); + uint16_t segments = (uint16_t)utilities::floorf(millimeters_of_travel / static_cast(args_.mm_per_arc_segment)); if (segments == 0) segments = 1; /* @@ -252,7 +246,7 @@ void prusa::mc_arc_3_10_0(float* position, float* target, float* offset, float f for (i = 1; i < segments; i++) { // Increment (segments-1) - if (count < cs.n_arc_correction) { + if (count < args_.n_arc_correction) { // Apply vector rotation matrix r_axisi = r_axis0 * sin_T + r_axis1 * cos_T; r_axis0 = r_axis0 * cos_T - r_axis1 * sin_T; @@ -327,39 +321,39 @@ void prusa::mc_arc_3_11_0(float* position, float* target, float* offset, float f float rt_x = target[X_AXIS] - center_axis_x; float rt_y = target[Y_AXIS] - center_axis_y; // 20200419 - Add a variable that will be used to hold the arc segment length - float mm_per_arc_segment = cs.mm_per_arc_segment; + float mm_per_arc_segment = static_cast(args_.mm_per_arc_segment); // 20210109 - Add a variable to hold the n_arc_correction value - uint8_t n_arc_correction = cs.n_arc_correction; + uint8_t n_arc_correction = args_.n_arc_correction; // CCW angle between position and target from circle center. Only one atan2() trig computation required. float angular_travel_total = (float)utilities::atan2((double)r_axis_x * rt_y - (double)r_axis_y * rt_x, (double)r_axis_x * rt_x + (double)r_axis_y * rt_y); if (angular_travel_total < 0) { angular_travel_total += 2.0f * PI_FLOAT; } - if (cs.min_arc_segments > 0) + if (args_.min_arc_segments > 0) { // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation // Do this before converting the angular travel for clockwise rotation - mm_per_arc_segment = radius * ((2.0f * PI_FLOAT) / cs.min_arc_segments); + mm_per_arc_segment = radius * ((2.0f * PI_FLOAT) / args_.min_arc_segments); } - if (cs.arc_segments_per_sec > 0) + if (args_.arc_segments_per_sec > 0) { // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation - float mm_per_arc_segment_sec = (feed_rate / 60.0f) * (1.0f / (float)cs.arc_segments_per_sec); + float mm_per_arc_segment_sec = (feed_rate / 60.0f) * (1.0f / (float)args_.arc_segments_per_sec); if (mm_per_arc_segment_sec < mm_per_arc_segment) mm_per_arc_segment = mm_per_arc_segment_sec; } // Note: no need to check to see if min_mm_per_arc_segment is enabled or not (i.e. = 0), since mm_per_arc_segment can never be below 0. - if (mm_per_arc_segment < cs.min_mm_per_arc_segment) + if (mm_per_arc_segment < args_.min_mm_per_arc_segment) { // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined // This prevents a very high number of segments from being generated for curves of a short radius - mm_per_arc_segment = cs.min_mm_per_arc_segment; + mm_per_arc_segment = static_cast(args_.min_mm_per_arc_segment); } - else if (mm_per_arc_segment > cs.mm_per_arc_segment) { + else if (mm_per_arc_segment > args_.mm_per_arc_segment) { // 20210113 - This can be implemented in an else if since we can't be below the min AND above the max at the same time. // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined - mm_per_arc_segment = cs.mm_per_arc_segment; + mm_per_arc_segment = static_cast(args_.mm_per_arc_segment); } // Adjust the angular travel if the direction is clockwise @@ -420,7 +414,7 @@ void prusa::mc_arc_3_11_0(float* position, float* target, float* offset, float f r_axis_x = -offset[X_AXIS] * cos_Ti + offset[Y_AXIS] * sin_Ti; r_axis_y = -offset[X_AXIS] * sin_Ti - offset[Y_AXIS] * cos_Ti; // reset n_arc_correction - n_arc_correction = cs.n_arc_correction; + n_arc_correction = args_.n_arc_correction; } else { // Calculate X and Y using the small angle approximation diff --git a/ArcWelderInverseProcessor/prusa.h b/ArcWelderInverseProcessor/prusa.h index 2a22edf..17ee97e 100644 --- a/ArcWelderInverseProcessor/prusa.h +++ b/ArcWelderInverseProcessor/prusa.h @@ -43,21 +43,6 @@ #include #include -struct ConfigurationStore { - ConfigurationStore() { - mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; - min_mm_per_arc_segment = DEFAULT_MIN_MM_PER_ARC_SEGMENT; - min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; - arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; - n_arc_correction = DEFAULT_N_ARC_CORRECTIONS; - } - float mm_per_arc_segment; // This value is ALWAYS used. - float min_mm_per_arc_segment; // if less than or equal to 0, this is disabled - int min_arc_segments; // If less than or equal to zero, this is disabled - double arc_segments_per_sec; // If less than or equal to zero, this is disabled - int n_arc_correction; - -}; class prusa : public firmware { @@ -76,7 +61,6 @@ private: /// /// A struct representing the prusa configuration store. Note: I didn't add the trailing underscore so this variable name will match the original source algorithm name. /// - ConfigurationStore cs; typedef void(prusa::*mc_arc_func)(float* position, float* target, float* offset, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder); void mc_arc_3_10_0(float* position, float* target, float* offset, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder); void mc_arc_3_11_0(float* position, float* target, float* offset, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder); diff --git a/ArcWelderInverseProcessor/repetier.cpp b/ArcWelderInverseProcessor/repetier.cpp index 2471478..f3feb61 100644 --- a/ArcWelderInverseProcessor/repetier.cpp +++ b/ArcWelderInverseProcessor/repetier.cpp @@ -48,11 +48,11 @@ void repetier::apply_arguments() switch (repetier_version_) { case repetier::repetier_firmware_versions::V1_0_5: - used_arguments = { "mm_per_arc_segment", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; arc_ = &repetier::arc_1_0_5; break; default: - used_arguments = { "mm_per_arc_segment", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; arc_ = &repetier::arc_1_0_4; break; } @@ -76,25 +76,11 @@ firmware_arguments repetier::get_default_arguments_for_current_version() const default_args.mm_per_arc_segment = 1.0f; default_args.n_arc_correction = 25; default_args.min_arc_segments = 24; - // Inactive Settings - default_args.min_arc_segments = 0; - default_args.arc_segments_per_r = 0; - default_args.min_mm_per_arc_segment = 0; - default_args.arc_segments_per_sec = 0; - // Settings that do not apply - default_args.mm_max_arc_error = 0; break; default: // Active Settings default_args.mm_per_arc_segment = 1.0f; default_args.n_arc_correction = 25; - // Inactive Settings - default_args.min_arc_segments = 0; - default_args.arc_segments_per_r = 0; - default_args.min_mm_per_arc_segment = 0; - default_args.arc_segments_per_sec = 0; - // Settings that do not apply - default_args.mm_max_arc_error = 0; break; } return default_args; diff --git a/ArcWelderInverseProcessor/smoothieware.cpp b/ArcWelderInverseProcessor/smoothieware.cpp index a96c88d..43b8c3c 100644 --- a/ArcWelderInverseProcessor/smoothieware.cpp +++ b/ArcWelderInverseProcessor/smoothieware.cpp @@ -42,6 +42,7 @@ smoothieware::smoothieware(firmware_arguments args) : firmware(args) { apply_arguments(); }; + void smoothieware::apply_arguments() { static const std::vector smoothieware_firmware_version_names{ "2021-06-19" }; @@ -53,7 +54,7 @@ void smoothieware::apply_arguments() //{ //default: append_arc_ = &smoothieware::append_arc_2021_06_19; - used_arguments = { "mm_per_arc_segment", "mm_max_arc_error", "n_arc_correction", "g90_g91_influences_extruder" }; + used_arguments = { FIRMWARE_ARGUMENT_MM_PER_ARC_SEGMENT, FIRMWARE_ARGUMENT_MM_MAX_ARC_ERROR, FIRMWARE_ARGUMENT_N_ARC_CORRECTION, FIRMWARE_ARGUMENT_G90_G91_INFLUENCES_EXTRUDER }; //break; //} diff --git a/GcodeProcessorLib/fpconv.h b/GcodeProcessorLib/fpconv.h index 8afcb21..29af997 100644 --- a/GcodeProcessorLib/fpconv.h +++ b/GcodeProcessorLib/fpconv.h @@ -52,6 +52,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef FPCONV_H #define FPCONV_H + +#define FPCONV_COPYRIGHT_STRING "Fpconv is an algorithm for producing fast floating point strings, which was added with the following notice: Copyright (C) 2014 Milo Yip. The original fpconv algorithm provides the following notice: Copyright(c) 2013 Andreas Samoljuk." + /* Fast and accurate double to string conversion based on Florian Loitsch's * Grisu-algorithm[1]. * diff --git a/GcodeProcessorLib/utilities.cpp b/GcodeProcessorLib/utilities.cpp index c0cc6c8..d16f8f4 100644 --- a/GcodeProcessorLib/utilities.cpp +++ b/GcodeProcessorLib/utilities.cpp @@ -291,6 +291,11 @@ std::string utilities::join(const std::vector strings, std::string } return output; } +/* Might need this later +bool utilities::contains(const std::string source, const std::string substring) +{ + return source.find(substring, 0) != std::string::npos; +}*/ std::istream& utilities::safe_get_line(std::istream& is, std::string& t) { @@ -471,6 +476,16 @@ bool utilities::get_temp_file_path_for_file(const std::string& file_path, std::s return true; } +bool utilities::does_file_exist(const std::string& file_path) +{ + FILE* file; + if (file = fopen(file_path.c_str(), "r")) { + fclose(file); + return true; + } + return false; +} + double utilities::hypot(double x, double y) { if (x < 0) x = -x; @@ -703,10 +718,13 @@ bool case_insensitive_compare(std::string& str1, std::string& str2) */ std::string utilities::replace(std::string subject, const std::string& search, const std::string& replace) { - size_t pos = 0; - while ((pos = subject.find(search, pos)) != std::string::npos) { - subject.replace(pos, search.length(), replace); - pos += replace.length(); + if (search.length() > 0) + { + size_t pos = 0; + while ((pos = subject.find(search, pos)) != std::string::npos) { + subject.replace(pos, search.length(), replace); + pos += replace.length(); + } } return subject; } diff --git a/GcodeProcessorLib/utilities.h b/GcodeProcessorLib/utilities.h index 7aa45b0..a71a36e 100644 --- a/GcodeProcessorLib/utilities.h +++ b/GcodeProcessorLib/utilities.h @@ -86,7 +86,7 @@ namespace utilities{ std::string join(const std::string* strings, size_t length, std::string sep); std::string join(const std::vector strings, std::string sep); - + // bool contains(const std::string source, const std::string substring); // Might need this later std::istream& safe_get_line(std::istream& is, std::string& t); std::string center(std::string input, int width); @@ -105,6 +105,8 @@ namespace utilities{ std::string create_uuid(); + bool does_file_exist(const std::string& file_path); + bool get_temp_file_path_for_file(const std::string& file_path, std::string& temp_file_path); double hypot(double x, double y); diff --git a/TCLAP/TCLAP.vcxproj b/TCLAP/TCLAP.vcxproj index 6b577ac..e6563e5 100644 --- a/TCLAP/TCLAP.vcxproj +++ b/TCLAP/TCLAP.vcxproj @@ -219,6 +219,7 @@ + diff --git a/TCLAP/TCLAP.vcxproj.filters b/TCLAP/TCLAP.vcxproj.filters index 3b2bed8..b9cc9ab 100644 --- a/TCLAP/TCLAP.vcxproj.filters +++ b/TCLAP/TCLAP.vcxproj.filters @@ -98,5 +98,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/TCLAP/tclap/tclap_version.h b/TCLAP/tclap/tclap_version.h new file mode 100644 index 0000000..ab366e8 --- /dev/null +++ b/TCLAP/tclap/tclap_version.h @@ -0,0 +1,3 @@ +#pragma once +#define TCLAP_VERSION_STRING "1.4" +#define TCLAP_COPYRIGHT_STRING "TCLAP: a templatized c++ command line parser, Copyright(C) 2017-2021 Google LLC, Copyright(C) 2012-2016 Daniel Aarno, Copyright(C) 2003-2012 Michael E. Smoot." diff --git a/readme.md b/readme.md index 2e8c947..66682e1 100644 --- a/readme.md +++ b/readme.md @@ -50,14 +50,29 @@ That will replace thing.gcode with a welded version of the file. **Creating a new file** -If you want your original file preserved, you can specify a target path like so: +If you want your original file preserved, you can specify a target path. +Windows example: + +``` +ArcWelder thing.gcode thing.aw.gcode +``` + +Linux/Raspbian example: ``` -C:\ArcWelder.exe C:\thing.gcode c:\thing.aw.gcode +./ArcWelder thing.gcode thing.aw.gcode ``` That would create a new file called thing.aw.gcode and would leave the thing.gcode file alone. +You can also supply a path for the source and target gcode files: + +``` +ArcWelder c:\my_gcode\thing.gcode c:\my_gcode\arc_welded_files\thing.aw.gcode +``` + +Note: You may need to enclose the paths in quotes, for example, if there are any spaces. + ## ArcWelder Console Help The console program will output all of the options with the following command for Windows: @@ -86,7 +101,7 @@ For some printers, sending a G90 or G91 command also changes the E axis mode. T * Default: Disabled * Short Parameter: -g * Long Parameter: --g90-influences-extruder -* Example: ```ArcWelder -g "C:\thing.gcode"``` +* Example: ```ArcWelder "C:\thing.gcode" -g``` ### Resolution (Maximum Path Deviation) ArcWelder is able to compress line segments into gcode by taking advantage of the fact that a bunch of tiny line segments can, when viewed from a distance, approximate a curve. However, a true curved path will never match up exactly with a bunch of straight lines, so ArcWelder needs a bit of play in order to create arc commands. The *resolution argument* tells ArcWelder how much leeway it has with the original toolpath to make an arc. Increasing this value will result in more compression, and reducing it will improve accuracy. It is a trade-off, but one that most slicers implement anyway in order to prevent too many tiny movements from overwhelming your firmware. In fact, ArcWelder can produce toolpaths that are more accurate than simply merging short segments together, making it less 'lossy' than slicer resolution settings. @@ -97,9 +112,10 @@ Values above 0.1 are not recommended, as you may encounter overlapping toolpaths * Type: Value (millimeters) * Default: 0.05 (+- 0.025) +* Restrictions: Only values greater than 0 are allowed. * Short Parameter: -r= * Long Parameter: --resolution-mm= -* Example: ```ArcWelder -r=0.1``` +* Example: ```ArcWelder "C:\thing.gcode" -r=0.1``` ### Path Tolerance Percent (length) This parameter allows you control how much the length of the final arc can deviate from the original toolpath. The default value of 5% is absolutely fine in most cases, even though that sounds like a lot. The key thing to remember here is that your firmware will break the G2/G3 commands into many small segments, essentially reversing the process, so the path length in your firmware will match the original path much more closely. @@ -108,18 +124,20 @@ Originally, this setting was added as a safety feature to prevent prevent bad ar * Type: Value (percent) * Default: 0.05 (5%) +* Restrictions: Only values greater than 0 (0%) and less than 1.0 (100%) are allowed. * Short Parameter: -t= * Long Parameter: --path-tolerance-percent= -* Example: ```ArcWelder --path-tolerance-percent=0.10``` +* Example: ```ArcWelder "C:\thing.gcode" --path-tolerance-percent=0.10``` ### Maximum Arc Radius Allows you to control the maximum radius arc that will be generated with ArcWelder. This was added as a safety feature to prevent giant arcs from being generated for essentially straight lines. ArcWelder does have built-in detection to prevent colinear lines from being turned into arcs, but slight deviations due to the precision of the gcodes (usually fixed to 3 decimal places) can cause arcs to be generated where straight lines would do. Typically no adjustments are necessary from the defaults, but you can adjust this value if you want. -* Type: Value (percent) -* Default: 1000000.0 (1000000.0 millimeters or 1 kilometer) +* Type: Value (decimal, millimeters) +* Default: 9999.0mm +* Restrictions: Only values greater than 0.0 are allowed. * Short Parameter: -m= * Long Parameter: --max-radius-mm= -* Example: ```ArcWelder --max-radius-mm=1000.0``` +* Example: ```ArcWelder "C:\thing.gcode" --max-radius-mm=1000.0``` ### Allow 3D Arcs This option allows G2/G3 commands to be generated when using vase mode. This is an experimental option, and it's possible that there are some unknown firmware issues when adding Z coordinates to arc commands. That being said, I've gotten pretty good results from this option. At some point, this will be enabled by default. @@ -128,49 +146,57 @@ This option allows G2/G3 commands to be generated when using vase mode. This is * Default: Disabled * Short Parameter: -z * Long Parameter: --allow-3d-arcs -* Example: ```ArcWelder --allow-3d-arcs``` +* Example: ```ArcWelder "C:\thing.gcode" --allow-3d-arcs``` ### Allow Travel Arcs -This option allows G2/G3 commands to be generated when for travel moves. In general, most travel moves will not be converted for the average 3D print. However, for plotters or CNC, or certain slicers that perform wipe actions while retracting, this feature can be useful. This is an experimental option. +This option allows G2/G3 commands to be generated when for travel moves (moves without any extrusion). In general, most travel moves will not be converted for the average 3D print. However, for plotters or CNC, or certain slicers that perform wipe actions while retracting, this feature can be useful. This is an experimental option. + +Note: When using the allow-travel-arcs option, you will see separate statistics for the travel move conversion, or a message indicating that no travel moves were converted. * Type: Flag * Default: False * Short Parameter: -y * Long Parameter: --allow-travel-arcs -* Example: ```ArcWelder --allow-travel-arcs``` +* Example: ```ArcWelder "C:\thing.gcode" --allow-travel-arcs``` ### Allow Dynamic Precision Not all gcode has the same precision for X, Y, and Z parameters. Enabling this option will cause the precision to grow as ArcWelder encounters gcodes with higher precision. This may increase gcode size somewhat, depending on the precision of the gcode commands in your file. -**Important Note**: This option used to be the default, but in some cases I've seen files with unusually high precision. If it gets too high, the resulting gcode may overrun the gcode buffer size, causing prints to fail. For that reason, this option has been disabled by default. I've only seen a few cases where this happens, and it's always been due to custom start/end gcode with extremely high precision. +**Important Note**: This option used to be the default, but in some cases I've seen files with unusually high precision. If it gets too high, the resulting gcode may overrun the gcode buffer size, causing prints to fail. For that reason, this option has been disabled by default. I've only seen a few cases where this happens, and it's always been due to custom start/end gcode with extremely high precision. See the Maximum Gcode Length section for more details. * Type: Flag * Default: Disabled * Short Parameter: -d * Long Parameter: --allow-dynamic-precision -* Example: ```ArcWelder --allow-dynamic-precision``` +* Example: ```ArcWelder "C:\thing.gcode" --allow-dynamic-precision``` ### Default XYZ Precision -ArcWelder outputs fixed precision for X, Y, Z, I, and J parameters. 99% of the time the default of 3 decimal places is just fine. If you need (want) more or less precision, you can alter this value. In general, I do not recommend a value below 3 or above 5. +ArcWelder outputs fixed precision for X, Y, Z, I, and J parameters. 99% of the time the default of 3 decimal places is just fine. If you need (want) more or less precision, you can alter this value. + +Note: that when combined with the --allow-dynamic-precision argument, this represents the minimum precision. It will grow if Arc Welder encounters gcode commands with a higher precision. -Note that when combined with the --allow-dynamic-precision argument, this represents the minimum precision. It will grow if Arc Welder encounters gcode commands with a higher precision. +**Important Note**: Some firmware isn't capable of executing gcodes that are too long. Increasing the precision will produce longer gcodes. See the Maximum Gcode Length section for more details. * Type: Value (integer decimal places) * Default: 3 (3 decimals, example: 1.001) +* Restrictions: Allowed values are 3, 4, 5, or 6. * Short Parameter: -x= * Long Parameter: --default-xyz-precision= -* Example: ```ArcWelder --default-xyz-precision=5``` +* Example: ```ArcWelder "C:\thing.gcode" --default-xyz-precision=5``` ### Default E Precision Arc Welder outputs fixed precision for the E parameter (extruder travel). 99% of the time the default of 5 decimal places is what you want. If you need (want) more or less precision, you can alter this value. In general, I do not recommend a value below 3 or above 5. Note, that when combined with the --allow-dynamic-precision argument, this represents the minimum precision. It will grow if Arc Welder encounters gcode commands with a higher precision. +**Important Note**: Some firmware isn't capable of executing gcodes that are too long. Increasing the precision will produce longer gcodes. See the Maximum Gcode Length section for more details. + * Type: Value (integer decimal places) * Default: 5 (5 decimals, example: 1.00001) +* Restrictions: Allowed values are 3, 4, 5, or 6. * Short Parameter: -e= * Long Parameter: --default-e-precision= -* Example: ```ArcWelder --default-e-precision=3``` +* Example: ```ArcWelder "C:\thing.gcode" --default-e-precision=3``` ### Firmware Compensation **Important**: Do **NOT** enable firmware compensation unless you are sure you need it! Print quality and compression will suffer if it is enabled needlessly. @@ -188,9 +214,10 @@ This is the default length of a segment in your firmware. This setting MUST mat * Type: Value (millimeters) * Default: 0 (disabled) +* Restrictions: Only values greater than or equal to 0.0 are allowed. If set greater than 0, min-arc-segments must also be set. * Short Parameter: -s= * Long Parameter: --mm-per-arc-segment= -* Example: ```ArcWelder --mm-per-arc-segment=1.0``` +* Example: ```ArcWelder "C:\thing.gcode" --mm-per-arc-segment=1.0 --min-arc-segments=14``` #### Minimum Arc Segments This specifies the minimum number of segments that a circle of the same radius must have and is the parameter that determines how much compensation will be applied. This setting was inspired by the Marlin 2.0 arc interpolation algorithm and attempts to follow it as closely as possible. The higher the value, the more compensation will be applied, and the less compression you will get. A minimum of 14 is recommended. Values above 24 are NOT recommended. In general, this should be set as low as possible. @@ -199,9 +226,10 @@ If ArcWelder detects that a generated arc would have fewer segments than specifi * Type: Value * Default: 0 (disabled) +* Restrictions: Only values greater than or equal to 0.0 are allowed. If set greater than 0, mm-per-arc-segment must also be set. * Short Parameter: -a= * Long Parameter: --min-arc-segments= -* Example: ```ArcWelder --min-arc-segments=14``` +* Example: ```ArcWelder "C:\thing.gcode" --mm-per-arc-segment=1.0 --min-arc-segments=14``` #### Firmware Compensation Example If you need to enable firmware compensation because you notice that small arcs appear flat, I recommend you start with the following settings: @@ -216,31 +244,47 @@ This feature allows ArcWelder to abort an arc if the extrusion rate changes by m * Type: Value * Default: 0.05 (5.0%) +* Restrictions: Only values greater than or equal to 0.0 are allowed. * Short Parameter: -v= (0.05 = 5.0%, 0 to disable) * Long Parameter: --extrusion-rate-variance-percent= -* Example: ```ArcWelder --extrusion-rate-variance-percent=0.025``` +* Example: ```ArcWelder "C:\thing.gcode" --extrusion-rate-variance-percent=0.025``` #### Maximum Gcode Length Some firmware has a problem with long gcode commands, and G2/G3 commands are some of the longest. You can specify a maximum gcode length to prevent long commands from being generated, which will reduce compression by a tiny amount. +Non-zero values less than 31 are not allowed. + * Type: Value * Default: 0 (no limit) +* Restrictions: Can be set to 0, or values > 30. * Short Parameter: -c= * Long Parameter: --max-gcode-length= -* Example: ```ArcWelder --max-gcode-length=50``` +* Example: ```ArcWelder "C:\thing.gcode" --max-gcode-length=50``` -### Progress Type +#### Progress Type This setting allows you to control the type of progress messages the ArcWelder console application will display. There are three options: * SIMPLE - This is the default setting. Here is a sample simple progress message: ```Progress: 21.9% complete - Estimated 35 of 45 seconds remaing.``` * FULL - This will show a much more detailed message, which is useful for any applications that which to scrape the detailed progress messages. Here is a sample full progress message: ```Progress: percent_complete:100.00, seconds_elapsed:0.01, seconds_remaining:0.00, gcodes_processed: 4320, current_file_line: 4320, points_compressed: 2092, arcs_created: 81, arcs_aborted_by_flowrate: 59, num_firmware_compensations: 0, num_gcode_length_exceptions: 0, compression_ratio: 2.27, size_reduction: 55.96%``` * NONE - No progress messages will be shown. -* Type: Flag +* Type: Value * Default: SIMPLE -* Short Parameter: -P -* Long Parameter: --progress-type -* Example: ```ArcWelder --progress-type=FULL``` +* Short Parameter: -P= +* Long Parameter: --progress-type= +* Example: ```ArcWelder "C:\thing.gcode" --progress-type=FULL``` + +#### Log Level +When set, ArcWelder will log to the console. This can be used to track down issues, or to figure out exactly what ArcWelder is doing. + +**Important Note:** Setting the log level could cause a huge amount of data to be outputted to the console, and will cause ArcWelder to be slow. I recommend you redirect the console output to speed things up if you use the DEBUG, VERBOSE or NOSET log levels. + +* Type: Value +* Default: INFO +* Short Parameter: -l= +* Long Parameter: --log-level= +* Example: ```ArcWelder "C:\thing.gcode" --log-level=DEBUG``` + ## Slicer Integrations @@ -341,26 +385,28 @@ Currently there are 5 different firmware types available: MARLIN_1, MARLIN_2, R * Default: MARLIN_2 * Short Parameter: -f= * Long Parameter: --firmware-type= -* Example: ```--firmware-type==PRUSA``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --firmware-type==MARLIN_1``` #### Firmware Version Use this argument to specify the firmware version. Not all versions are supported. To see a list of available versions for each firmware type, use the --help argument. Note that the LATEST_RELEASE parameter does not always point to the most recent version, but rather the most recent stable release. Also, the PRUSA firmware version V3_11_0 is not yet released, but was added assuming new arc interpolation parameters from the roadmap will be included. +Note: You may need to specify the firmware-type argument to choose the appropriate firmware version. + * Type: Value * Default: LATEST_RELEASE * Short Parameter: -V= * Long Parameter: --firmware_version= -* Example: ```--firmware_version==V1_1_9_1``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --firmware-type==MARLIN_1 --firmware_version==1.1.9.1``` #### Print Firmware Defaults and Supported Settings Prints all avaliable settings and defaults for the provided firmware type and version. When using this parameter, all other valid parameters will be ignored. -Note: Supply the --firmware_type and --firmware_version to see the defaults and supported settings. +Note: Supply the --firmware_type and --firmware_version to see the defaults and supported settings. When printing firmware defaults, you don't need to supply a source file location. * Type: Flag * Short Parameter: -p * Long Parameter: --print-firmware-defaults -* Example: ```ArcStraightener --print-firmware-defaults --firmware_type=PRUSA --firmware_version==V1_1_9_1``` +* Example: ```ArcStraightener --print-firmware-defaults --firmware_type=MARLIN_1 --firmware_version==1.1.9.1``` ## Firmware Specific Settings The different firmware types and versions all support different arc interpolation settings. See the Print Firmware Defaults section for info on how to discover what paramaters a specific firmware version supports, as well as the defaults. @@ -372,7 +418,7 @@ Sets the firmware's G90/G91 influences extruder axis behavior. By default this * Default: Set By Firmware Type and Version * Short Parameter: -g= * Long Parameter: --g90-influences-extruder= -* Example: ```ArcStraightener --firmware_type=PRUSA --firmware_version==V1_1_9_1 --g90-influences-extruder=TRUE``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --firmware_type=PRUSA --firmware_version==V1_1_9_1 --g90-influences-extruder=TRUE``` Note, in the example above, the default behavior of the prusa firmware is overridden by the argument. @@ -383,7 +429,7 @@ This is the default segment length for arc interpolation. Depending on the impl * Default: 1.0 * Short Parameter: -m= * Long Parameter: --mm-per-arc-segment= -* Example: ```ArcStraightener --mm-per-arc-segment=0.5``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --mm-per-arc-segment=0.5``` #### Max Arc Segment MM This is the maximum length an arc segment can be. @@ -392,7 +438,16 @@ This is the maximum length an arc segment can be. * Default: 1.0 * Short Parameter: -d= * Long Parameter: --max-arc-segment-mm= -* Example: ```ArcStraightener --max-arc-segment-mm=0.5``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --max-arc-segment-mm=0.5``` + +#### Arc Segments Per R +This is the maximum length an arc segment can be. It's basically the same as Max Arc Segment MM, but is used in different firmware + +* Type: Value (millimeters) +* Default: 0 (disabled) +* Short Parameter: -i= +* Long Parameter: --arc-segments-per-r= +* Example: ```ArcStraightener "C:\thing.aw.gcode" --arc-segments-per-r=0.5``` #### Min Arc Segment MM This is the Minimum length an arc segment can be. @@ -401,7 +456,7 @@ This is the Minimum length an arc segment can be. * Default: 1.0 * Short Parameter: -n= * Long Parameter: --min-mm-per-arc-segment= -* Example: ```ArcStraightener --min-mm-per-arc-segment=0.5``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --min-mm-per-arc-segment=0.5``` #### Min Arc Segments The minimum number of segments within a circle of the same radius as the arc. Can be used to increase detail on small arcs. @@ -410,7 +465,7 @@ The minimum number of segments within a circle of the same radius as the arc. C * Default: 24 * Short Parameter: -r= * Long Parameter: --min-arc-segments= -* Example: ```ArcStraightener --min-arc-segments=24``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --min-arc-segments=24``` #### Min Circle Segments This is a the same as the Min Arc Segments setting used in some firmware versions. Can be used to increase detail on small arcs. @@ -419,7 +474,7 @@ This is a the same as the Min Arc Segments setting used in some firmware version * Default: 72 * Short Parameter: -a= * Long Parameter: --min-circle-segments= -* Example: ```ArcStraightener --min-circle-segments=24``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --min-circle-segments=24``` #### N Arc Correction The number of segments that will be interpolated using a small angle approximation before true sin/cos corrections are applied. A value less than or equal to 1 will disable this feature. Note that enabling this can cause visible interpolation errors, especially on arcs with a very large radius. Disabling this setting could cause performance issues on slower hardware. @@ -428,7 +483,7 @@ The number of segments that will be interpolated using a small angle approximati * Default: 24 * Short Parameter: -c= * Long Parameter: --n-arc-correction= -* Example: ```ArcStraightener --n-arc-correction=8``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --n-arc-correction=8``` #### Arc Segments Per Second The number of segments per second. This will produce a constant number of arcs, clamped between mm-per-arc-segment and min-mm-per-arc-segment. Can be used to prevent stuttering when printing very quickly. A value less than or equal to 0 will disable this feature. @@ -437,7 +492,7 @@ The number of segments per second. This will produce a constant number of arcs, * Default: 0 (Disabled) * Short Parameter: -s= * Long Parameter: --arc-segments-per-second= -* Example: ```ArcStraightener --arc-segments-per-second=24``` +* Example: ```ArcStraightener "C:\thing.aw.gcode" --arc-segments-per-second=24``` #### MM Max Arc Error I'm not 100% sure exactly what this does, but I believe it attempts to limit the drift in the arc path to this value in MM. When I know more I will update this description. This currently is only used in Smoothieware. Set to 0 to disable. @@ -446,4 +501,4 @@ I'm not 100% sure exactly what this does, but I believe it attempts to limit the * Default: 0.01 * Short Parameter: -e= * Long Parameter: --mm-max-arc-error= -* Example: ```ArcStraightener --mm-max-arc-error=0.25``` \ No newline at end of file +* Example: ```ArcStraightener "C:\thing.aw.gcode" --mm-max-arc-error=0.25``` \ No newline at end of file -- cgit v1.2.3